org.wso2.carbon.appfactory.jenkins.build.RestBasedJenkinsCIConnector.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.appfactory.jenkins.build.RestBasedJenkinsCIConnector.java

Source

/*
 * Copyright 2005-2011 WSO2, Inc. (http://wso2.com)
 *
 *      Licensed under the Apache License, Version 2.0 (the "License");
 *      you may not use this file except in compliance with the License.
 *      You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *      Unless required by applicable law or agreed to in writing, software
 *      distributed under the License is distributed on an "AS IS" BASIS,
 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *      See the License for the specific language governing permissions and
 *      limitations under the License.
 */

package org.wso2.carbon.appfactory.jenkins.build;

import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.om.util.AXIOMUtil;
import org.apache.axiom.om.xpath.AXIOMXPath;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.jaxen.JaxenException;
import org.wso2.carbon.appfactory.common.AppFactoryConstants;
import org.wso2.carbon.appfactory.common.AppFactoryException;
import org.wso2.carbon.appfactory.common.beans.RuntimeBean;
import org.wso2.carbon.appfactory.common.util.AppFactoryUtil;
import org.wso2.carbon.appfactory.core.BuildDriverListener;
import org.wso2.carbon.appfactory.core.apptype.ApplicationTypeBean;
import org.wso2.carbon.appfactory.core.apptype.ApplicationTypeManager;
import org.wso2.carbon.appfactory.core.dao.ApplicationDAO;
import org.wso2.carbon.appfactory.core.dto.Statistic;
import org.wso2.carbon.appfactory.core.internal.ServiceHolder;
import org.wso2.carbon.appfactory.core.runtime.RuntimeManager;
import org.wso2.carbon.appfactory.core.util.AppFactoryCoreUtil;
import org.wso2.carbon.appfactory.eventing.AppFactoryEventException;
import org.wso2.carbon.appfactory.eventing.Event;
import org.wso2.carbon.appfactory.eventing.EventNotifier;
import org.wso2.carbon.appfactory.eventing.builder.utils.ContinousIntegrationEventBuilderUtil;
import org.wso2.carbon.appfactory.eventing.utils.EventingConstants;
import org.wso2.carbon.appfactory.jenkins.build.internal.ServiceContainer;
import org.wso2.carbon.appfactory.repository.mgt.RepositoryMgtException;
import org.wso2.carbon.appfactory.repository.mgt.RepositoryProvider;
import org.wso2.carbon.appfactory.repository.mgt.internal.Util;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.user.core.UserCoreConstants;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;

import javax.net.ssl.SSLContext;
import javax.xml.stream.XMLStreamException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Connects to a jenkins server using its 'Remote API'.
 */
public class RestBasedJenkinsCIConnector {

    private static final Log log = LogFactory.getLog(RestBasedJenkinsCIConnector.class);
    public static final String URL_SUFFIX_FORMAT_CREATE_JOB = "/job/%s/createItem";
    public static final long MILLISECONDS_PER_SECOND = 1000L;
    private static RestBasedJenkinsCIConnector restBasedJenkinsCIConnector;
    private static final int MAX_SUCCESS_HTTP_STATUS_CODE = 299;

    static {
        try {
            restBasedJenkinsCIConnector = new RestBasedJenkinsCIConnector();
        } catch (AppFactoryException e) {
            String msg = "Error occurred while instantiating the RestBasedJenkinsCIConnector";
            log.error(msg, e);
            throw new RuntimeException(msg, e);
        }
    }

    /**
     * The http client used to connect jenkins.
     */
    private HttpClient httpClient;

    /**
     * Base url of the jenkins
     */
    private String jenkinsUrl;

    /**
     * Flag weather this connector needs to authenticate it self.
     */
    private boolean authenticate;

    /**
     * User who authenticate with jenkins rest api
     */
    private String username;
    /**
     * API key or password to authenticate user
     */
    private String apiKeyOrPassword;

    /**
     * Specify whether the host name need to be verified or not
     */
    private boolean allowAllHostNameVerifier;

    /**
     * Specify the max number of connection per route in httpclient
     */
    private int defaultMaxConnectionsPerRoute;

    /**
     * Specify the max number of total connection in httpclient
     */
    private int maxTotalConnections;

    /**
     * Returns an instance of RestBasedJenkinsCIConnector
     *
     * @return instance of RestBasedJenkinsCIConnector
     * @throws AppFactoryException when reading from appfactory.xml
     */
    public static RestBasedJenkinsCIConnector getInstance() throws AppFactoryException {
        return restBasedJenkinsCIConnector;
    }

    /**
     * Private constructor for singleton class
     *
     * @throws AppFactoryException when reading from appfactory.xml
     */
    private RestBasedJenkinsCIConnector() throws AppFactoryException {

        this.authenticate = Boolean.parseBoolean(AppFactoryUtil.getAppfactoryConfiguration()
                .getFirstProperty(JenkinsCIConstants.AUTHENTICATE_CONFIG_SELECTOR));

        this.username = AppFactoryUtil.getAppfactoryConfiguration()
                .getFirstProperty(JenkinsCIConstants.JENKINS_SERVER_ADMIN_USERNAME);

        this.apiKeyOrPassword = AppFactoryUtil.getAppfactoryConfiguration()
                .getFirstProperty(JenkinsCIConstants.JENKINS_SERVER_ADMIN_PASSWORD);

        this.allowAllHostNameVerifier = Boolean.parseBoolean(AppFactoryUtil.getAppfactoryConfiguration()
                .getFirstProperty(JenkinsCIConstants.ALLOW_ALL_HOSTNAME_VERIFIER));

        this.defaultMaxConnectionsPerRoute = Integer.parseInt(AppFactoryUtil.getAppfactoryConfiguration()
                .getFirstProperty(JenkinsCIConstants.DEFAULT_MAX_CONNECTIONS_PER_ROUTE));

        this.maxTotalConnections = Integer.parseInt(AppFactoryUtil.getAppfactoryConfiguration()
                .getFirstProperty(JenkinsCIConstants.MAX_TOTAL_CONNECTIONS));

        if (log.isDebugEnabled()) {
            log.debug(String.format("Authenticate : %s", this.authenticate));
            log.debug(String.format("Jenkins user name : %s", this.username));
        }

        ThreadSafeClientConnManager threadSafeClientConnManager = new ThreadSafeClientConnManager();
        threadSafeClientConnManager.setDefaultMaxPerRoute(this.defaultMaxConnectionsPerRoute);
        threadSafeClientConnManager.setMaxTotal(this.maxTotalConnections);
        this.httpClient = new DefaultHttpClient(threadSafeClientConnManager);
    }

    /**
     * Create the HttpContext and disable host verification
     *
     * @return
     * @throws AppFactoryException
     */
    public HttpContext getHttpContext() throws AppFactoryException {

        HttpContext httpContext = new BasicHttpContext();
        if (this.allowAllHostNameVerifier) {
            SSLContext sslContext;
            try {
                sslContext = SSLContext.getInstance(SSLSocketFactory.TLS);
                sslContext.init(null, null, null);
            } catch (KeyManagementException e) {
                String msg = "Error while initializing ssl context for http client";
                log.error(msg, e);
                throw new AppFactoryException(msg, e);
            } catch (NoSuchAlgorithmException e) {
                String msg = "Error while initializing ssl context for http client";
                log.error(msg, e);
                throw new AppFactoryException(msg, e);
            }
            SSLSocketFactory sf = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            Scheme sch = new Scheme("https", 443, sf);
            httpClient.getConnectionManager().getSchemeRegistry().register(sch);
        }
        return httpContext;
    }

    /**
     * Get jenkins URL by {@code tenantDomain}. Since we are using a bucket strategy to select jenkins cluster, and
     * bucket(therefore jenkins cluster) depends on the {@code tenantDomain}. correct {@code tenantDomain} should be
     * passed here.
     *
     * @param tenantDomain tenant Domain
     * @return jenkins url
     * @throws AppFactoryException
     */
    public String getJenkinsUrl(String tenantDomain) throws AppFactoryException {
        int tenantBucketId = ServiceContainer.getBucketSelectingStrategy().getTenantBucketId(tenantDomain);
        String bucketClusterId = ServiceContainer.getClusterSelectingStrategy().getBucketClusterId(tenantBucketId);
        if (StringUtils.isBlank(bucketClusterId)) {
            throw new IllegalArgumentException("Jenkins server url is unspecified for bucket:" + tenantBucketId);
        }
        return bucketClusterId;
    }

    /**
     * Create a job in Jenkins
     *
     * @param jobName      name of the job
     * @param jobParams    Job configuration parameters
     * @param tenantDomain Tenant domain of application
     * @throws AppFactoryException if an error occurs.
     */
    public void createJob(String jobName, Map<String, String> jobParams, String tenantDomain)
            throws AppFactoryException {

        OMElement jobConfiguration = new JobConfigurator(jobParams)
                .configure(jobParams.get(JenkinsCIConstants.APPLICATION_EXTENSION));

        List<NameValuePair> queryParams = new ArrayList<NameValuePair>();
        queryParams.add(new BasicNameValuePair(AppFactoryConstants.JOB_NAME_KEY, jobName));
        HttpPost createJob;
        HttpResponse createJobResponse = null;

        try {
            createJob = createPost(String.format(URL_SUFFIX_FORMAT_CREATE_JOB, tenantDomain), queryParams,
                    new StringEntity(jobConfiguration.toStringWithConsume(), "text/xml", "utf-8"), tenantDomain);
            createJobResponse = httpClient.execute(createJob, getHttpContext());
            int httpStatusCode = createJobResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                createJobResponse = resendRequest(createJob, createJobResponse);
                httpStatusCode = createJobResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                String errorMsg = "Unable to create the job : " + jobName + ". jenkins returned, http status : "
                        + httpStatusCode;
                log.error(errorMsg);
                throw new AppFactoryException(errorMsg);
            }
        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpPost method for creating job for job : " + jobName
                    + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpPost method for creating job for job : " + jobName
                    + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (XMLStreamException e) {
            String msg = "Error while converting OMElement to string when creating job for job : " + jobName
                    + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } finally {
            if (createJobResponse != null) {
                try {
                    EntityUtils.consume(createJobResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming the create job response for job : " + jobName
                            + " in tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }
    }

    /**
     * Create tenant job. This will create "Folder Job"(folder with the name of {@code jobName} in
     * $JENKINS_HOME/jobs directory) to represent the tenant in the jenkins
     *
     * @param jobName           job name.
     * @param jobConfiguration  job configuration
     * @param tenantDomain      tenant domain
     * @throws AppFactoryException
     */
    public void createTenantJob(String jobName, OMElement jobConfiguration, String tenantDomain)
            throws AppFactoryException {

        List<NameValuePair> queryParams = new ArrayList<NameValuePair>();
        queryParams.add(new BasicNameValuePair(AppFactoryConstants.JOB_NAME_KEY, jobName));
        HttpPost createJob;
        HttpResponse createJobResponse = null;

        try {
            createJob = createPost("/createItem", queryParams,
                    new StringEntity(jobConfiguration.toStringWithConsume(), "text/xml", "utf-8"), tenantDomain);
            createJobResponse = httpClient.execute(createJob, getHttpContext());
            int httpStatusCode = createJobResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                createJobResponse = resendRequest(createJob, createJobResponse);
                httpStatusCode = createJobResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                String errorMsg = "Unable to create the job : " + jobName + ". jenkins returned, http status : "
                        + httpStatusCode;
                log.error(errorMsg);
                throw new AppFactoryException(errorMsg);
            }
        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpPost method for creating job for job : " + jobName
                    + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpPost method for creating job for job : " + jobName
                    + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (XMLStreamException e) {
            String msg = "Error while converting OMElement to string when creating job for job : " + jobName
                    + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } finally {
            if (createJobResponse != null) {
                try {
                    EntityUtils.consume(createJobResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming the create job response for job : " + jobName
                            + " in tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }
    }

    /**
     * Checks weather a job exists in Jenkins server
     *
     * @param applicationId id of the application
     * @param version       version of the application
     * @param tenantDomain  tenant domain, to which the application belongs
     * @return true if job exits, false otherwise.
     * @throws AppFactoryException if an error occurs.
     */
    public boolean isJobExists(String applicationId, String version, String tenantDomain, String userName)
            throws AppFactoryException {

        String jobName = ServiceHolder.getContinuousIntegrationSystemDriver().getJobName(applicationId, version,
                MultitenantUtils.getTenantAwareUsername(userName));
        final String wrapperTag = "JobNames";

        List<NameValuePair> queryParameters = new ArrayList<NameValuePair>();
        queryParameters.add(new BasicNameValuePair("wrapper", wrapperTag));
        queryParameters.add(new BasicNameValuePair("xpath", String.format("/*/job/name[text()='%s']", jobName)));

        HttpGet checkJobExistsMethod = createGet("/job/" + tenantDomain + "/api/xml", queryParameters,
                tenantDomain);

        boolean isExists = false;
        HttpResponse jobExistResponse = null;

        try {
            jobExistResponse = httpClient.execute(checkJobExistsMethod, getHttpContext());
            int httpStatusCode = jobExistResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                jobExistResponse = resendRequest(checkJobExistsMethod, jobExistResponse);
                httpStatusCode = jobExistResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                final String errorMsg = "Unable to check the existence of job " + jobName
                        + ". jenkins returned, http status : " + httpStatusCode;
                log.error(errorMsg);
                throw new AppFactoryException(errorMsg);
            }

            StAXOMBuilder builder = new StAXOMBuilder(jobExistResponse.getEntity().getContent());
            isExists = builder.getDocumentElement().getChildElements().hasNext();

        } catch (XMLStreamException e) {
            String msg = "Error while creating StAXOMBuilder using the response of isJobExists method for application : "
                    + applicationId + " version : " + version + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpGet method for checking availability of job for application : "
                    + applicationId + " version : " + version + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpGet method for checking availability of job for application : "
                    + applicationId + " version : " + version + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } finally {
            if (jobExistResponse != null) {
                try {
                    EntityUtils.consume(jobExistResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming the response for is job exist request for application : "
                            + applicationId + " version : " + version + " in tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }
        return isExists;
    }

    /**
     * Deletes a job in jenkins
     *
     * @param jobName      name of the job
     * @param tenantDomain tenant domain, to which the application belongs
     * @return true if job exited on Jenkins and successfully deleted.
     * @throws AppFactoryException if an error occurs.
     */
    public boolean deleteJob(String jobName, String tenantDomain) throws AppFactoryException {

        HttpPost deleteJobMethod;
        deleteJobMethod = createPost(String.format("/job/" + tenantDomain + "/job/%s/doDelete", jobName), null,
                null, tenantDomain);
        int httpStatusCode = -1;
        HttpResponse deleteJobResponse = null;

        try {
            deleteJobResponse = httpClient.execute(deleteJobMethod, getHttpContext());
            httpStatusCode = deleteJobResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode) && HttpStatus.SC_MOVED_TEMPORARILY != httpStatusCode) {
                deleteJobResponse = resendRequest(deleteJobMethod, deleteJobResponse);
                httpStatusCode = deleteJobResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode) && HttpStatus.SC_MOVED_TEMPORARILY != httpStatusCode) {
                final String msg = "Unable to delete the job : " + jobName + ". jenkins returned http status : "
                        + httpStatusCode;
                log.error(msg);
                throw new AppFactoryException(msg);
            }

        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpPost method for deleting the job : " + jobName + " in tenant : "
                    + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpPost method for deleting the job : " + jobName + " in tenant : "
                    + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } finally {
            if (deleteJobResponse != null) {
                try {
                    EntityUtils.consume(deleteJobResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming delete job response for job : " + jobName + " in tenant : "
                            + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }
        return HttpStatus.SC_NOT_FOUND != httpStatusCode;
    }

    /**
     * Starts a build job available in Jenkins
     *
     * @param applicationId id of the application
     * @param version       version of the application
     * @param doDeploy      specifies whether the artifact need to be deployed or not
     * @param stageName     lifecycle stage of the application i.e: dev, prod, test
     * @param tagName
     * @param tenantDomain  tenant domain, to which the application belongs
     * @param userName      username of the user, who triggered the build
     * @param repoFrom      type of repository. i.e: master, fork
     * @throws AppFactoryException
     */
    public void startBuild(String applicationId, String version, boolean doDeploy, String stageName, String tagName,
            String tenantDomain, String userName, String repoFrom) throws AppFactoryException {

        userName = MultitenantUtils.getTenantAwareUsername(userName);
        String jobName;
        if (AppFactoryConstants.FORK_REPOSITORY.equals(repoFrom)) {
            jobName = ServiceHolder.getContinuousIntegrationSystemDriver().getJobName(applicationId, version,
                    userName);
        } else {
            jobName = ServiceHolder.getContinuousIntegrationSystemDriver().getJobName(applicationId, version, null);
        }
        String artifactType = ApplicationDAO.getInstance().getApplicationType(applicationId);
        boolean isFreestyle = false;

        try {
            isFreestyle = AppFactoryCoreUtil.isFreestyleNonBuilableProject(artifactType);
        } catch (AppFactoryException e) {
            log.error("Error while checking whether the apptype is freestyle or not", e);
            //continue the flow as non free style app
        }

        List<NameValuePair> parameters = new ArrayList<NameValuePair>();
        parameters.add(new BasicNameValuePair(AppFactoryConstants.IS_AUTOMATIC, AppFactoryConstants.STRING_FALSE));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.DO_DEPLOY, Boolean.toString(doDeploy)));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.DEPLOY_STAGE, stageName));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.BUILD_REPO_FROM, repoFrom));
        String tenantUserName = userName + UserCoreConstants.TENANT_DOMAIN_COMBINER + tenantDomain;
        parameters.add(new BasicNameValuePair(AppFactoryConstants.TENANT_USER_NAME, tenantUserName));

        if (tagName != null && !tagName.equals(AppFactoryConstants.EMPTY_STRING)) {
            parameters.add(new BasicNameValuePair(AppFactoryConstants.PERSIST_ARTIFACT, String.valueOf(true)));
            parameters.add(new BasicNameValuePair(AppFactoryConstants.TAG_NAME, tagName));
        } else {
            parameters.add(new BasicNameValuePair(AppFactoryConstants.PERSIST_ARTIFACT, String.valueOf(false)));
        }

        HttpPost startBuildMethod;
        startBuildMethod = createPost(
                String.format("/job/" + tenantDomain + "/job/%s/buildWithParameters", jobName), parameters, null,
                tenantDomain);

        int httpStatusCode;
        HttpResponse buildResponse = null;
        try {
            buildResponse = httpClient.execute(startBuildMethod, getHttpContext());
            httpStatusCode = buildResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                buildResponse = resendRequest(startBuildMethod, buildResponse);
                httpStatusCode = buildResponse.getStatusLine().getStatusCode();
            }

            if (HttpStatus.SC_NOT_FOUND == httpStatusCode) {
                String repoType = ApplicationDAO.getInstance().getApplicationInfo(applicationId)
                        .getRepositoryType();
                RepositoryProvider repoProvider = Util.getRepositoryProvider(repoType);
                String repoURL;
                try {
                    repoURL = repoProvider.getAppRepositoryURL(applicationId, tenantDomain);
                } catch (RepositoryMgtException e) {
                    String msg = "Error while creating repository url for application : " + applicationId
                            + " version : " + version + " repo from : " + repoFrom + "in tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }

                ServiceContainer.getJenkinsCISystemDriver().createJob(applicationId, version, "", tenantDomain,
                        userName, repoURL, AppFactoryConstants.ORIGINAL_REPOSITORY);

                buildResponse = resendRequest(startBuildMethod, buildResponse);
                httpStatusCode = buildResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                String msg = "Error occurred with the http status code : " + httpStatusCode
                        + " while starting a build for application : " + applicationId + " version : " + version
                        + " in tenant : " + tenantDomain;
                log.error(msg);
                throw new AppFactoryException(msg);
            }

        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpPost method for starting a build for application : "
                    + applicationId + " version : " + version + " in tenant : " + tenantDomain;
            log.error(msg, e);
            if (!isFreestyle) {
                try {
                    addWallMessage(applicationId, tenantUserName, repoFrom, version, false, userName);
                } catch (AppFactoryEventException e1) {
                    log.error("Error while notifying wall notification about the build failure for application : "
                            + applicationId + " version : " + version + " in tenant : " + tenantDomain, e1);
                }
            }
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpPost method for starting a build for application : "
                    + applicationId + " version : " + version + " in tenant : " + tenantDomain;
            log.error(msg, e);
            if (!isFreestyle) {
                try {
                    addWallMessage(applicationId, tenantUserName, repoFrom, version, false, userName);
                } catch (AppFactoryEventException e1) {
                    log.error("Error while notifying wall notification about the build failure for application : "
                            + applicationId + " version : " + version + " in tenant : " + tenantDomain, e1);
                }
            }
            throw new AppFactoryException(msg, e);
        } finally {
            if (buildResponse != null) {
                try {
                    EntityUtils.consume(buildResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming the Response of build request for application : "
                            + applicationId + " version : " + version + " in tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }

        if (!isFreestyle) {
            try {
                addWallMessage(applicationId, tenantUserName, repoFrom, version, true, userName);
            } catch (AppFactoryEventException e) {
                log.error("Error while notifying wall notification about  for application : " + applicationId
                        + " version : " + version + " in tenant : " + tenantDomain, e);
            }
        }

        Iterator<BuildDriverListener> buildDriverListeners = ServiceContainer.getBuildDriverListeners().iterator();
        while (buildDriverListeners.hasNext()) {
            BuildDriverListener listener = buildDriverListeners.next();
            listener.onBuildStart(applicationId, version, "", userName, repoFrom, tenantDomain);
        }
    }

    /**
     * Method to send the build notification to the wall
     *
     * @param applicationId  id of the application
     * @param tenantUserName user's username with tenant domain
     * @param repoFrom       repository type. i.e: master, fork
     * @param version        version of the application
     * @param isBuildSuccess status of the build
     * @param userName       name of the user
     * @throws AppFactoryEventException
     */
    private void addWallMessage(String applicationId, String tenantUserName, String repoFrom, String version,
            boolean isBuildSuccess, String userName) throws AppFactoryEventException {
        String repoType, infoMessage;
        Event.Category category;

        String correlationKey = applicationId + AppFactoryConstants.MINUS + tenantUserName
                + AppFactoryConstants.MINUS + repoFrom + AppFactoryConstants.MINUS + version;

        if (EventingConstants.ORIGINAL_REPO_FORM.equals(repoFrom)) {
            repoType = AppFactoryConstants.MASTER_REPO;
        } else {
            repoType = AppFactoryConstants.FORKED_REPO;
        }

        if (isBuildSuccess) {
            infoMessage = "Build started for " + version + " in " + repoType + " by " + userName;
            category = Event.Category.INFO;
        } else {
            infoMessage = "Unable to start build for " + version + " in " + repoType + " by " + userName;
            infoMessage.concat("\n Tenant domain: " + tenantUserName);
            category = Event.Category.ERROR;
        }

        EventNotifier.getInstance().notify(ContinousIntegrationEventBuilderUtil
                .buildTriggerBuildEvent(applicationId, repoFrom, userName, infoMessage, category, correlationKey));
    }

    /**
     * //TODO NEED TO CHANGE,
     * Method to get the status of the build
     *
     * @param buildUrl     url of the build
     * @param tenantDomain tenant domain, to which the application belongs
     * @return status of the given build
     * @throws AppFactoryException
     */
    public String getbuildStatus(String buildUrl, String tenantDomain) throws AppFactoryException {

        String buildStatus = AppFactoryConstants.BUILD_STATUS_UNKNOWN;
        HttpGet checkJobExistsMethod = createGetByBaseUrl(buildUrl, "api/xml", null);

        HttpResponse getBuildStatusResponse = null;
        try {
            getBuildStatusResponse = httpClient.execute(checkJobExistsMethod, getHttpContext());
            int httpStatusCode = getBuildStatusResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                getBuildStatusResponse = resendRequest(checkJobExistsMethod, getBuildStatusResponse);
                httpStatusCode = getBuildStatusResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                final String errorMsg = "Unable to check the status of build : " + buildUrl
                        + ". jenkins returned, http status : " + httpStatusCode;
                log.error(errorMsg);
                throw new AppFactoryException(errorMsg);
            }

            StAXOMBuilder builder = new StAXOMBuilder(getBuildStatusResponse.getEntity().getContent());
            OMElement resultElement = builder.getDocumentElement();

            if (resultElement != null) {
                if (AppFactoryConstants.STRING_FALSE.equals(getValueUsingXpath(resultElement, "/*/building"))) {
                    buildStatus = getValueUsingXpath(resultElement, "/*/result");
                } else {
                    buildStatus = AppFactoryConstants.BUILD_STATUS_BUILDING;
                }
            }

        } catch (XMLStreamException e) {
            String msg = "Error while building StAXOMBuilder for the response of build status request of build url : "
                    + buildUrl + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpGet method for getting the build status of build url : "
                    + buildUrl + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpGet method for getting the build status of build url : "
                    + buildUrl + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } finally {
            if (getBuildStatusResponse != null) {
                try {
                    EntityUtils.consume(getBuildStatusResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming get build status response for build url : " + buildUrl
                            + " in tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }
        return buildStatus;
    }

    /**
     * Method to get the list of build urls for a given job
     *
     * @param jobName      name of the job
     * @param tenantDomain tenant domain, to which the application belongs
     * @return the list of build urls for a specifig job
     * @throws AppFactoryException
     */
    public List<String> getBuildUrls(String jobName, String tenantDomain) throws AppFactoryException {

        List<String> listOfUrls = new ArrayList<String>();
        final String wrapperTag = "Builds";
        List<NameValuePair> queryParameters = new ArrayList<NameValuePair>();
        queryParameters.add(new BasicNameValuePair(AppFactoryConstants.WRAPPER_TAG_KEY, wrapperTag));
        queryParameters.add(new BasicNameValuePair(AppFactoryConstants.XPATH_EXPRESSION_KEY, "/*/build/url"));

        HttpGet getBuildsMethod = createGet(String.format("/job/%s/job/%s/api/xml", tenantDomain, jobName),
                queryParameters, tenantDomain);
        HttpResponse getBuildUrlResponse = null;

        try {
            getBuildUrlResponse = httpClient.execute(getBuildsMethod, getHttpContext());
            int httpStatusCode = getBuildUrlResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                getBuildUrlResponse = resendRequest(getBuildsMethod, getBuildUrlResponse);
                httpStatusCode = getBuildUrlResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                String errorMsg = "Unable to retrieve available build urls from jenkins for job : " + jobName
                        + ". jenkins returned, http status : " + httpStatusCode;
                log.error(errorMsg);
                throw new AppFactoryException(errorMsg);
            }

            StAXOMBuilder builder = new StAXOMBuilder(getBuildUrlResponse.getEntity().getContent());
            @SuppressWarnings("unchecked")
            Iterator<OMElement> urlElementsIte = builder.getDocumentElement().getChildElements();
            while (urlElementsIte.hasNext()) {
                OMElement urlElement = urlElementsIte.next();
                listOfUrls.add(urlElement.getText());
            }

        } catch (XMLStreamException e) {
            String msg = "Error while building StAXOMBuilder for get build url response for job : " + jobName
                    + " in tenant : " + tenantDomain;
            log.error(msg, e);
        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpGet method for getting the build urls of job : " + jobName
                    + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpGet method for getting the build urls of job : " + jobName
                    + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } finally {
            if (getBuildUrlResponse != null) {
                try {
                    EntityUtils.consume(getBuildUrlResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming get build url response for job : " + jobName
                            + " in tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }
        return listOfUrls;
    }

    /**
     * Returns the over all load of the jenkins server
     *
     * @param tenantDomain tenant domain
     * @return
     * @throws AppFactoryException
     */
    public List<Statistic> getOverallLoad(String tenantDomain) throws AppFactoryException {

        HttpGet overallLoad = createGet("/overallLoad/api/xml", null, tenantDomain);
        List<Statistic> list = new ArrayList<Statistic>();
        HttpResponse getOverallLoadResponse = null;

        try {
            getOverallLoadResponse = httpClient.execute(overallLoad, getHttpContext());
            int httpStatusCode = getOverallLoadResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                getOverallLoadResponse = resendRequest(overallLoad, getOverallLoadResponse);
                httpStatusCode = getOverallLoadResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                final String msg = "Unable to check the overall load of jenkins in tenant : " + tenantDomain
                        + ". jenkins returned, http status : " + httpStatusCode;
                log.error(msg);
                throw new AppFactoryException(msg);
            }

            StAXOMBuilder builder = new StAXOMBuilder(getOverallLoadResponse.getEntity().getContent());
            @SuppressWarnings("unchecked")
            Iterator<OMElement> elementIterator = (Iterator<OMElement>) builder.getDocumentElement()
                    .getChildElements();

            while (elementIterator.hasNext()) {
                OMElement statElement = elementIterator.next();
                String value = StringUtils.isEmpty(statElement.getText()) ? "-1" : statElement.getText();
                Statistic stat = new Statistic(statElement.getLocalName(), value);
                list.add(stat);
            }

        } catch (XMLStreamException e) {
            String msg = "Error while building StAXOMBuilder for get overall load response in tenant : "
                    + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpGet method for getting the overall load in tenant : "
                    + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpGet method for getting the overall load in tenant : "
                    + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } finally {
            if (getOverallLoadResponse != null) {
                try {
                    EntityUtils.consume(getOverallLoadResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming the get overall load response for tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }
        return list;
    }

    /**
     * This method will call jenkins to deploy the latest successfully built
     * artifact of the given job name
     *
     * @param jobName      job name of which the artifact is going to get deployed
     * @param artifactType artifact type (car/war) that is going to get deployed
     * @param stage        server Urls that we need to deploy the artifact into
     * @param tenantDomain tenant domain, to which the job belongs to
     * @param userName     user name of the user, who triggered the deployement
     * @param deployAction
     * @param repoFrom     specifies the repository type. i.e: master, fork
     * @throws AppFactoryException
     */
    public void deployLatestSuccessArtifact(String jobName, String artifactType, String stage, String tenantDomain,
            String userName, String deployAction, String repoFrom) throws AppFactoryException {

        String deployLatestSuccessArtifactUrl = "/plugin/appfactory-plugin/deployLatestSuccessArtifact";

        HttpPost deployLatestSuccessArtifactMethod;
        HttpResponse deployResponse = null;

        try {
            List<NameValuePair> parameters = new ArrayList<NameValuePair>();
            parameters.add(new BasicNameValuePair(AppFactoryConstants.ARTIFACT_TYPE, artifactType));
            ApplicationTypeBean applicationTypeBean = ApplicationTypeManager.getInstance()
                    .getApplicationTypeBean(artifactType);

            if (applicationTypeBean == null) {
                throw new AppFactoryException(
                        "Application Type details cannot be found for Artifact Type : " + artifactType
                                + " , Job Name : " + jobName + ", stage : " + stage + " for username: " + userName);
            }

            String runtimeNameForAppType = applicationTypeBean.getRuntimes()[0];
            RuntimeBean runtimeBean = RuntimeManager.getInstance().getRuntimeBean(runtimeNameForAppType);

            if (runtimeBean == null) {
                throw new AppFactoryException("Runtime details cannot be found for Artifact Type : " + artifactType
                        + " , Job Name : " + jobName + ", stage : " + stage + " for username: " + userName);
            }

            parameters.add(new BasicNameValuePair(AppFactoryConstants.TENANT_DOMAIN, tenantDomain));
            int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
            parameters.add(new BasicNameValuePair(AppFactoryConstants.TENANT_ID, Integer.toString(tenantId)));
            parameters.add(
                    new BasicNameValuePair(AppFactoryConstants.RUNTIME_NAME_FOR_APPTYPE, runtimeNameForAppType));
            parameters.add(new BasicNameValuePair(AppFactoryConstants.JOB_NAME, jobName));
            parameters.add(new BasicNameValuePair(AppFactoryConstants.DEPLOY_STAGE, stage));
            parameters.add(new BasicNameValuePair(AppFactoryConstants.DEPLOY_ACTION, deployAction));
            addAppTypeParameters(parameters, applicationTypeBean);
            addRunTimeParameters(stage, parameters, runtimeBean);
            parameters.add(new BasicNameValuePair(AppFactoryConstants.REPOSITORY_FROM, repoFrom));
            String tenantUserName = userName + UserCoreConstants.TENANT_DOMAIN_COMBINER + tenantDomain;
            parameters.add(new BasicNameValuePair(AppFactoryConstants.TENANT_USER_NAME, tenantUserName));

            deployLatestSuccessArtifactMethod = createPost(deployLatestSuccessArtifactUrl, parameters, null,
                    tenantDomain);
            deployResponse = httpClient.execute(deployLatestSuccessArtifactMethod, getHttpContext());
            int httpStatusCode = deployResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                deployResponse = resendRequest(deployLatestSuccessArtifactMethod, deployResponse);
                httpStatusCode = deployResponse.getStatusLine().getStatusCode();
            }

            log.info("status code for deploy latest success artifact type : " + artifactType + " job name : "
                    + jobName + " stage : " + stage + " in tenant : " + tenantDomain + " is " + httpStatusCode);
            if (!isSuccessfulStatusCode(httpStatusCode)) {
                String errorMsg = "Unable to deploy the latest success artifact. jenkins "
                        + "returned, http status : " + httpStatusCode;
                log.error(errorMsg);
                throw new AppFactoryException(errorMsg);
            }

        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpPost method for deploying the latest successful artifact for job : "
                    + jobName + " artifact type : " + artifactType + " in stage : " + stage + " in tenant : "
                    + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpPost method for deploying the latest successful artifact for job : "
                    + jobName + " artifact type : " + artifactType + " in stage : " + stage + " in tenant : "
                    + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } finally {
            if (deployResponse != null) {
                try {
                    EntityUtils.consume(deployResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming deploy latest success artifact response for job : "
                            + jobName + " of user : " + userName + " in tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }

    }

    /**
     * Add application type parameters to the map
     *
     * @param parameters parameter map to send to the jenkins
     * @param applicationTypeBean application type bean object
     */
    private void addAppTypeParameters(List<NameValuePair> parameters, ApplicationTypeBean applicationTypeBean) {
        parameters.add(new BasicNameValuePair(AppFactoryConstants.APPLICATION_EXTENSION,
                applicationTypeBean.getExtension()));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.DEPLOYER_CLASSNAME,
                applicationTypeBean.getDeployerClassName()));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.SERVER_DEPLOYMENT_PATHS,
                applicationTypeBean.getServerDeploymentPath()));
    }

    /**
      * deploy the promoted artifact
      *
      * @param jobName      name of the job
      * @param artifactType type of the artifact, which need to be deployed
      * @param stage        environment stage, to which the artifact need to be deployed
      * @param tenantDomain tenant domain, to which the application is belongs
      * @param userName     user name of the user, who promoted the application
      * @throws AppFactoryException
      */
    public void deployPromotedArtifact(String jobName, String artifactType, String stage, String tenantDomain,
            String userName) throws AppFactoryException {

        String deployPromotedArtifactUrl = "/plugin/appfactory-plugin/deployPromotedArtifact";
        ApplicationTypeBean applicationTypeBean = ApplicationTypeManager.getInstance()
                .getApplicationTypeBean(artifactType);

        if (applicationTypeBean == null) {
            throw new AppFactoryException("Application Type details cannot be found for job : " + jobName
                    + " artifact type : " + artifactType + " in tenant : " + tenantDomain);
        }

        String runtimeNameForAppType = applicationTypeBean.getRuntimes()[0];
        RuntimeBean runtimeBean = RuntimeManager.getInstance().getRuntimeBean(runtimeNameForAppType);

        if (runtimeBean == null) {
            throw new AppFactoryException("Runtime details cannot be found");
        }

        List<NameValuePair> parameters = new ArrayList<NameValuePair>();
        parameters.add(new BasicNameValuePair(AppFactoryConstants.TENANT_DOMAIN, tenantDomain));
        int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
        parameters.add(new BasicNameValuePair(AppFactoryConstants.TENANT_ID, Integer.toString(tenantId)));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.JOB_NAME, jobName));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.ARTIFACT_TYPE, artifactType));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.RUNTIME_NAME_FOR_APPTYPE, runtimeNameForAppType));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.DEPLOY_STAGE, stage));
        String tenantUserName = userName + UserCoreConstants.TENANT_DOMAIN_COMBINER + tenantDomain;
        parameters.add(new BasicNameValuePair(AppFactoryConstants.TENANT_USER_NAME, tenantUserName));

        addAppTypeParameters(parameters, applicationTypeBean);
        addRunTimeParameters(stage, parameters, runtimeBean);

        HttpPost deployPromotedArtifactMethod;
        HttpResponse deployResponse = null;
        deployPromotedArtifactMethod = createPost(deployPromotedArtifactUrl, parameters, null, tenantDomain);

        try {
            deployResponse = httpClient.execute(deployPromotedArtifactMethod, getHttpContext());
            int httpStatusCode = deployResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                deployResponse = resendRequest(deployPromotedArtifactMethod, deployResponse);
                httpStatusCode = deployResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                String errorMsg = "Unable to deploy the promoted artifact for job " + jobName
                        + ". jenkins returned, http status : " + httpStatusCode;
                log.error(errorMsg);
                throw new AppFactoryException(errorMsg);
            }
        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpPost method for deploying the promoted artifact for job : "
                    + jobName + " artifact type : " + artifactType + " in stage : " + stage + " in tenant : "
                    + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpPost method for deploying the promoted artifact for job : "
                    + jobName + " artifact type : " + artifactType + " in stage : " + stage + " in tenant : "
                    + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } finally {
            if (deployResponse != null) {
                try {
                    EntityUtils.consume(deployResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming deploy promoted artifact response for job : " + jobName
                            + " of user : " + userName + " in tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }
    }

    /**
     * This will extract pre configured mvn repo to tenant
     * @param tenantDomain
     * @throws AppFactoryException
     */
    public void extractMvnRepo(String tenantDomain) throws AppFactoryException {
        String extractMvnRepoUrl = "/plugin/appfactory-plugin/extractMvnRepo";
        List<NameValuePair> parameters = new ArrayList<NameValuePair>();
        parameters.add(new BasicNameValuePair(AppFactoryConstants.TENANT_DOMAIN, tenantDomain));
        HttpResponse extractResponse = null;
        HttpPost extractMvnRepoMethod = createPost(extractMvnRepoUrl, parameters, null, tenantDomain);
        try {
            extractResponse = httpClient.execute(extractMvnRepoMethod, getHttpContext());
            int httpStatusCode = extractResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                extractResponse = resendRequest(extractMvnRepoMethod, extractResponse);
                httpStatusCode = extractResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                String errorMsg = "Unable to extract pre configured maven repo for tenant: " + tenantDomain
                        + ". jenkins returned, http status : " + httpStatusCode;
                log.error(errorMsg);
                throw new AppFactoryException(errorMsg);
            }
        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpPost method for extract pre configured maven repo for tenant: "
                    + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpPost method for extract pre configured maven repo for tenant: "
                    + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } finally {
            if (extractResponse != null) {
                try {
                    EntityUtils.consume(extractResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming  extract pre configured maven repo for tenant: "
                            + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }
    }

    /**
     * Method to set an application auto buildable
     *
     * @param jobName        name of the job
     * @param repositoryType repository type
     * @param isAutoBuild    specify whether the application is auto buildable or not
     * @param pollingPeriod
     * @param tenantDomain   tenant domain, to which the application is belongs
     * @throws AppFactoryException
     */
    public void setJobAutoBuildable(String jobName, String repositoryType, boolean isAutoBuild, int pollingPeriod,
            String tenantDomain) throws AppFactoryException {
        OMElement configuration = getAutoBuildUpdatedConfiguration(jobName, repositoryType, isAutoBuild,
                pollingPeriod, tenantDomain);
        OMElement tmpConfiguration = configuration.cloneOMElement();
        setConfiguration(jobName, tmpConfiguration, tenantDomain);
        if (log.isDebugEnabled()) {
            log.debug("Job : " + jobName + " successfully configured for auto building " + isAutoBuild
                    + " in jenkins");
        }
    }

    /**
     * Method to get the auto build updated configuration
     *
     * @param jobName        name of the job
     * @param repositoryType repository type
     * @param isAutoBuild    specify whether the application is auto buildable or not
     * @param pollingPeriod
     * @param tenantDomain   tenant domain, to which the application is belongs
     * @return
     * @throws AppFactoryException
     */
    private OMElement getAutoBuildUpdatedConfiguration(String jobName, String repositoryType, boolean isAutoBuild,
            int pollingPeriod, String tenantDomain) throws AppFactoryException {

        HttpGet getFetchMethod = createGet(String.format("/job/%s/job/%s/config.xml", tenantDomain, jobName), null,
                tenantDomain);
        OMElement configurations = null;
        HttpResponse buildUpdateResponse = null;

        try {

            buildUpdateResponse = httpClient.execute(getFetchMethod, getHttpContext());
            int httpStatusCode = buildUpdateResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                buildUpdateResponse = resendRequest(getFetchMethod, buildUpdateResponse);
                httpStatusCode = buildUpdateResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                String errorMsg = "Unable to retrieve available config urls from jenkins for job : " + jobName
                        + ". jenkins returned, http status : " + httpStatusCode;
                log.error(errorMsg);
                throw new AppFactoryException(errorMsg);
            }

            StAXOMBuilder builder = new StAXOMBuilder(buildUpdateResponse.getEntity().getContent());
            configurations = builder.getDocumentElement();

            AXIOMXPath axiomxPath = new AXIOMXPath("//triggers");
            Object selectedObject = axiomxPath.selectSingleNode(configurations);
            if (isAutoBuild) {

                if (selectedObject != null) {
                    OMElement selectedNode = (OMElement) selectedObject;
                    selectedNode.detach();
                }

                StringBuilder payload = new StringBuilder(
                        "<triggers class=\"vector\">" + "<hudson.triggers.SCMTrigger>");
                if ("git".equals(repositoryType)) {
                    payload = payload.append("<spec></spec>");
                } else {
                    payload = payload.append("<spec>*/" + pollingPeriod + " * * * *</spec>");
                }
                payload = payload.append("</hudson.triggers.SCMTrigger>" + "</triggers>");
                OMElement triggerParam = AXIOMUtil.stringToOM(payload.toString());
                configurations.addChild(triggerParam);

            } else {
                if (selectedObject != null) {
                    OMElement selectedNode = (OMElement) selectedObject;
                    selectedNode.detach();
                }
            }

        } catch (XMLStreamException e) {
            String msg = "Error while building StAXOMBuilder for get auto build configuration response for job : "
                    + jobName + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (JaxenException e) {
            String msg = "Error while creating AXIOMXPath when getting the auto build updated configuration for job : "
                    + jobName + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpGet method for getting the auto build updated configuration for job : "
                    + jobName + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpGet method for getting the auto build updated configuration for job : "
                    + jobName + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } finally {
            if (buildUpdateResponse != null) {
                try {
                    EntityUtils.consume(buildUpdateResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming get auto build updated configuration response for job : "
                            + jobName + " for repository type : " + repositoryType + " in tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }
        return configurations;
    }

    /**
     * update the job configuration
     *
     * @param jobName          job name of which we need to update the configuration of
     * @param jobConfiguration new configurations that needs to be set
     * @param tenantDomain     tenant domain, to which the application is belongs
     * @throws AppFactoryException
     */
    private void setConfiguration(String jobName, OMElement jobConfiguration, String tenantDomain)
            throws AppFactoryException {

        List<NameValuePair> queryParams = new ArrayList<NameValuePair>();
        queryParams.add(new BasicNameValuePair(AppFactoryConstants.JOB_NAME_KEY, jobName));
        HttpPost createJob;
        HttpResponse setConfigurationResponse = null;

        try {
            createJob = createPost(String.format("/job/%s/job/%s/config.xml", tenantDomain, jobName), queryParams,
                    new StringEntity(jobConfiguration.toStringWithConsume(), "text/xml", "utf-8"), tenantDomain);
            setConfigurationResponse = httpClient.execute(createJob, getHttpContext());
            int httpStatusCode = setConfigurationResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                setConfigurationResponse = resendRequest(createJob, setConfigurationResponse);
                httpStatusCode = setConfigurationResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                String errorMsg = String.format(
                        "Unable to set configuration: [%s]. jenkins " + "returned, http status : %d", jobName,
                        httpStatusCode);
                log.error(errorMsg);
                throw new AppFactoryException(errorMsg);
            }

        } catch (ClientProtocolException e) {
            String msg = "Error while executing HttpGet method for setting configuration for job : " + jobName
                    + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (IOException e) {
            String msg = "Error while executing HttpGet method for setting configuration for job : " + jobName
                    + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (XMLStreamException e) {
            String msg = "Error while converting OMElement to string when creating job for job : " + jobName
                    + " in tenant : " + tenantDomain;
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } finally {
            if (setConfigurationResponse != null) {
                try {
                    EntityUtils.consume(setConfigurationResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming set configuration response for job : " + jobName
                            + " in tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }

    }

    /**
     * Set the application auto deployable in jenkins
     *
     * @param jobName          name of the job
     * @param isAutoDeployable specifies whether the application need to auto deploy or not
     * @param tenantDomain     tenant domain, to which the application belongs
     * @throws AppFactoryException
     */
    public void setJobAutoDeployable(String jobName, boolean isAutoDeployable, String tenantDomain)
            throws AppFactoryException {

        OMElement configuration = getAutoDeployUpdatedConfiguration(jobName, isAutoDeployable, tenantDomain);
        OMElement tmpConfiguration = configuration.cloneOMElement();
        setConfiguration(jobName, tmpConfiguration, tenantDomain);
        if (log.isDebugEnabled()) {
            log.debug("Job : " + jobName + " successfully configured for auto deploying " + isAutoDeployable
                    + " in jenkins");
        }
    }

    /**
     * Method to get the auto deploy updated configuration
     *
     * @param jobName      name of the job
     * @param isAutoDeploy specifies whether the application need to be auto deployed or not
     * @param tenantDomain tenant domain, to which the application belongs
     * @return
     * @throws AppFactoryException
     */
    private OMElement getAutoDeployUpdatedConfiguration(String jobName, boolean isAutoDeploy, String tenantDomain)
            throws AppFactoryException {

        OMElement configurations = null;
        HttpResponse autoDeployUpdateResponse = null;
        int httpStatusCode;

        HttpGet getFetchMethod = createGet(String.format("/job/%s/job/%s/config.xml", tenantDomain, jobName), null,
                tenantDomain);

        try {
            autoDeployUpdateResponse = httpClient.execute(getFetchMethod, getHttpContext());
            httpStatusCode = autoDeployUpdateResponse.getStatusLine().getStatusCode();

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                autoDeployUpdateResponse = resendRequest(getFetchMethod, autoDeployUpdateResponse);
                httpStatusCode = autoDeployUpdateResponse.getStatusLine().getStatusCode();
            }

            if (!isSuccessfulStatusCode(httpStatusCode)) {
                String errorMsg = "Unable to retrieve available config urls from jenkins for job : " + jobName
                        + ". jenkins returned, http status : " + httpStatusCode;
                log.error(errorMsg);
                throw new AppFactoryException(errorMsg);
            }

            StAXOMBuilder builder = new StAXOMBuilder(autoDeployUpdateResponse.getEntity().getContent());
            configurations = builder.getDocumentElement();

            String paramValue;
            if (isAutoDeploy) {
                paramValue = AppFactoryConstants.STRING_TRUE;
            } else {
                paramValue = AppFactoryConstants.STRING_FALSE;
            }

            AXIOMXPath axiomxPath = new AXIOMXPath(
                    "//hudson.model.ParametersDefinitionProperty[1]/parameterDefinitions[1]/hudson.model.StringParameterDefinition[name='isAutomatic']/defaultValue");
            Object selectedObject = axiomxPath.selectSingleNode(configurations);

            if (selectedObject != null) {
                OMElement selectedNode = (OMElement) selectedObject;
                selectedNode.setText(paramValue);
            } else {
                AXIOMXPath axiomP = new AXIOMXPath(
                        "//hudson.model.ParametersDefinitionProperty[1]/parameterDefinitions[1]");
                Object parameterDefsObject = axiomP.selectSingleNode(configurations);
                OMElement parameterDefsNode = (OMElement) parameterDefsObject;

                String payload = "<isAutomatic>" + paramValue + "</isAutomatic>";
                OMElement triggerParam = AXIOMUtil.stringToOM(payload);
                parameterDefsNode.addChild(triggerParam);
            }

        } catch (XMLStreamException e) {
            String errorMsg = "Unable to retrieve available jobs from jenkins";
            log.error(errorMsg, e);
            throw new AppFactoryException(errorMsg, e);
        } catch (JaxenException e) {
            String errorMsg = "Error occurred while updating the job configuration for parameter \"isAutomatic\" for"
                    + " tenant: " + tenantDomain;
            log.error(errorMsg, e);
            throw new AppFactoryException(errorMsg, e);
        } catch (IOException e) {
            String errorMsg = "Unable to retrieve available jobs from jenkins for tenant: " + tenantDomain;
            log.error(errorMsg, e);
            throw new AppFactoryException(errorMsg, e);
        } finally {
            if (autoDeployUpdateResponse != null) {
                try {
                    EntityUtils.consume(autoDeployUpdateResponse.getEntity());
                } catch (IOException e) {
                    String msg = "Error while consuming auto deploy update configuration response for job : "
                            + jobName + " in tenant : " + tenantDomain;
                    log.error(msg, e);
                    throw new AppFactoryException(msg, e);
                }
            }
        }

        return configurations;
    }

    private HttpGet createGetByBaseUrl(String baseUrl, String relativePath, List<NameValuePair> queryParameters)
            throws AppFactoryException {
        String query = null;
        HttpGet get;

        if (queryParameters != null) {
            query = URLEncodedUtils.format(queryParameters, HTTP.UTF_8);
        }
        try {
            URL url = new URL(baseUrl);
            URI uri = URIUtils.createURI(url.getProtocol(), url.getHost(), url.getPort(), relativePath, query,
                    null);

            get = new HttpGet(uri);
            if (authenticate) {
                get.addHeader(BasicScheme.authenticate(
                        new UsernamePasswordCredentials(this.username, this.apiKeyOrPassword), HTTP.UTF_8, false));
            }

        } catch (MalformedURLException e) {
            String msg = "Error while generating URL for the path : " + baseUrl
                    + " during the creation of HttpGet method";
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (URISyntaxException e) {
            String msg = "Error while constructing the URI for url : " + baseUrl
                    + " during the creation of HttpGet method";
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        }

        return get;
    }

    /**
     * Util method to create a http get method
     *
     * @param urlFragment     the url fragment
     * @param queryParameters query parameters
     * @param tenantDomain    tenant domain, to which the application is belongs
     * @return a {@link HttpGet}
     */
    private HttpGet createGet(String urlFragment, List<NameValuePair> queryParameters, String tenantDomain)
            throws AppFactoryException {

        String query = null;
        HttpGet get;

        if (queryParameters != null) {
            query = URLEncodedUtils.format(queryParameters, HTTP.UTF_8);
        }
        try {
            URL url = new URL(getJenkinsUrl(tenantDomain));
            URI uri = URIUtils.createURI(url.getProtocol(), url.getHost(), url.getPort(), urlFragment, query, null);
            get = new HttpGet(uri);
            if (authenticate) {
                get.addHeader(BasicScheme.authenticate(
                        new UsernamePasswordCredentials(this.username, this.apiKeyOrPassword), HTTP.UTF_8, false));
            }

        } catch (MalformedURLException e) {
            String msg = "Error while generating URL for the path : " + urlFragment + " in tenant : " + tenantDomain
                    + " during the creation of HttpGet method";
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (URISyntaxException e) {
            String msg = "Error while constructing the URI for url fragment " + urlFragment + " in tenant : "
                    + tenantDomain + " during the creation of HttpGet method";
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        }
        return get;
    }

    /**
     * Util method to create a POST method
     *
     * @param urlFragment     Url fragments.
     * @param queryParameters Query parameters.
     * @param httpEntity
     * @param tenantDomain    Tenant Domain of application
     * @return a {@link HttpPost}
     */
    private HttpPost createPost(String urlFragment, List<NameValuePair> queryParameters, HttpEntity httpEntity,
            String tenantDomain) throws AppFactoryException {

        String query = "";
        HttpPost post;

        if (queryParameters != null) {
            query = URLEncodedUtils.format(queryParameters, HTTP.UTF_8);
        }
        try {
            URL url = new URL(getJenkinsUrl(tenantDomain));
            URI uri = URIUtils.createURI(url.getProtocol(), url.getHost(), url.getPort(), urlFragment, query, null);
            post = new HttpPost(uri);

            if (httpEntity != null) {
                post.setEntity(httpEntity);
            }

            if (authenticate) {
                post.addHeader(BasicScheme.authenticate(
                        new UsernamePasswordCredentials(this.username, this.apiKeyOrPassword), HTTP.UTF_8, false));
            }
        } catch (MalformedURLException e) {
            String msg = "Error while generating URL for the path : " + urlFragment + " in tenant : " + tenantDomain
                    + " during the creation of HttpGet method";
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (URISyntaxException e) {
            String msg = "Error while constructing the URI for tenant : " + tenantDomain
                    + " during the creation of " + "HttpPosts method";
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        }
        return post;
    }

    /**
     * @param template
     * @param selector
     * @return
     * @throws AppFactoryException
     */
    private String getValueUsingXpath(OMElement template, String selector) throws AppFactoryException {

        String value = null;
        try {
            AXIOMXPath axiomxPath = new AXIOMXPath(selector);
            Object selectedObject = axiomxPath.selectSingleNode(template);

            if (selectedObject != null && selectedObject instanceof OMElement) {
                OMElement selectedElement = (OMElement) selectedObject;
                value = selectedElement.getText();
            } else {
                log.warn("Unable to find xml element matching selector : " + selector);
            }

        } catch (Exception ex) {
            throw new AppFactoryException("Unable to set value to job config ", ex);
        }
        return value;
    }

    /**
     * When jenkins tenant is unloaded the requests cannot be fulfilled. So this
     * method will be used to resend the Get requests
     *
     * @param method       method to be retried
     * @param httpResponse http response of the previous request
     * @return httpStatusCode
     */
    private HttpResponse resendRequest(HttpGet method, HttpResponse httpResponse) throws AppFactoryException {

        int httpStatusCode;
        int retryCount = Integer.parseInt(AppFactoryUtil.getAppfactoryConfiguration()
                .getFirstProperty(JenkinsCIConstants.JENKINS_CLIENT_RETRY_COUNT));
        int retryDelay = Integer.parseInt(AppFactoryUtil.getAppfactoryConfiguration()
                .getFirstProperty(JenkinsCIConstants.JENKINS_CLIENT_RETRY_DELAY));
        log.info("Jenkins client retry count :" + retryCount + " and retry delay in seconds :" + retryDelay
                + " for " + method.getMethod());

        //TODO - Send mail to cloud
        try {
            // retry retryCount times to process the request
            for (int i = 0; i < retryCount; i++) {
                Thread.sleep(MILLISECONDS_PER_SECOND * retryDelay); // sleep retryDelay seconds, giving jenkins
                // time to load the tenant
                if (log.isDebugEnabled()) {
                    log.debug("Resending request(" + i + ") started for GET");
                }

                if (httpResponse != null) {
                    EntityUtils.consume(httpResponse.getEntity());
                }

                httpResponse = httpClient.execute(method, getHttpContext());
                httpStatusCode = httpResponse.getStatusLine().getStatusCode();

                // In the new jenkins release the response is always 201 or 302
                if (HttpStatus.SC_OK == httpStatusCode || HttpStatus.SC_CREATED == httpStatusCode
                        || HttpStatus.SC_MOVED_TEMPORARILY == httpStatusCode) {
                    if (log.isDebugEnabled()) {
                        log.debug("Break resending since " + httpStatusCode);
                    }
                    break;
                }
                if (log.isDebugEnabled()) {
                    log.debug("Resent GET request(" + i + ") failed with response code " + httpStatusCode);
                }
            }
        } catch (IOException e) {
            String msg = "Error while resending the request to URI : " + method.getURI();
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (InterruptedException e) {
            String msg = "Error while resending the request to URI : " + method.getURI();
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        }
        return httpResponse;
    }

    /**
     * When jenkins tenant is unloaded the requests cannot be fulfilled. So this
     * method will be used to resend the Post requests
     *
     * @param method       method to be retried
     * @param httpResponse http response of the previous request
     * @return httpStatusCode
     */
    private HttpResponse resendRequest(HttpPost method, HttpResponse httpResponse) throws AppFactoryException {

        int httpStatusCode;
        int retryCount = Integer.parseInt(AppFactoryUtil.getAppfactoryConfiguration()
                .getFirstProperty(JenkinsCIConstants.JENKINS_CLIENT_RETRY_COUNT));
        int retryDelay = Integer.parseInt(AppFactoryUtil.getAppfactoryConfiguration()
                .getFirstProperty(JenkinsCIConstants.JENKINS_CLIENT_RETRY_DELAY));
        log.info("Jenkins client retry count :" + retryCount + " and retry delay in seconds :" + retryDelay
                + " for " + method.getMethod());
        try {
            // retry retryCount times to process the request
            for (int i = 0; i < retryCount; i++) {
                Thread.sleep(MILLISECONDS_PER_SECOND * retryDelay); // sleep retryDelay seconds, giving jenkins
                // time to load the tenant
                if (log.isDebugEnabled()) {
                    log.debug("Resending request(" + i + ") started for POST");
                }
                if (httpResponse != null) {
                    EntityUtils.consume(httpResponse.getEntity());
                }
                HttpContext httpContext = getHttpContext();
                httpResponse = httpClient.execute(method, httpContext);
                httpStatusCode = httpResponse.getStatusLine().getStatusCode();
                // In the new jenkins release the response is always 201 or 302
                if (HttpStatus.SC_OK == httpStatusCode || HttpStatus.SC_CREATED == httpStatusCode
                        || HttpStatus.SC_MOVED_TEMPORARILY == httpStatusCode) {
                    if (log.isDebugEnabled()) {
                        log.debug("Break resending since " + httpStatusCode);
                    }
                    break;
                }
                if (log.isDebugEnabled()) {
                    log.debug("Resent POST request(" + i + ") failed with response code " + httpStatusCode);
                }
            }
        } catch (IOException e) {
            String msg = "Error while resending the request to URI : " + method.getURI();
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        } catch (InterruptedException e) {
            String msg = "Error while resending the request to URI : " + method.getURI();
            log.error(msg, e);
            throw new AppFactoryException(msg, e);
        }
        return httpResponse;
    }

    /**
     * Add runtime specific parameters to the parameter map
     *
     * @param stage       current stage of the application version
     * @param parameters  list of name value pair to sent to jenkins
     * @param runtimeBean runtime bean that we need to add parameters from
     */
    private void addRunTimeParameters(String stage, List<NameValuePair> parameters, RuntimeBean runtimeBean) {
        parameters.add(new BasicNameValuePair(AppFactoryConstants.RUNTIME_ALIAS_PREFIX,
                runtimeBean.getAliasPrefix() + stage));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.RUNTIME_CARTRIDGE_TYPE_PREFIX,
                runtimeBean.getCartridgeTypePrefix() + stage));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.PAAS_REPOSITORY_URL_PATTERN,
                runtimeBean.getPaasRepositoryURLPattern()));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.RUNTIME_DEPLOYMENT_POLICY,
                runtimeBean.getDeploymentPolicy()));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.RUNTIME_AUTOSCALE_POLICY,
                runtimeBean.getAutoscalePolicy()));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.RUNTIME_DATA_CARTRIDGE_TYPE,
                runtimeBean.getDataCartridgeType()));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.RUNTIME_DATA_CARTRIDGE_ALIAS,
                runtimeBean.getDataCartridgeAlias()));
        parameters.add(new BasicNameValuePair(AppFactoryConstants.RUNTIME_SUBSCRIBE_ON_DEPLOYMENT,
                Boolean.toString(runtimeBean.getSubscribeOnDeployment())));
    }

    /**
     * Check if the given status code is in 2xx range.
     *
     * @param httpStatusCode - status code to be checked
     * @return true if status code is in 2xx range
     */
    private boolean isSuccessfulStatusCode(int httpStatusCode) {
        return (httpStatusCode >= HttpStatus.SC_OK && httpStatusCode < MAX_SUCCESS_HTTP_STATUS_CODE);
    }

}