org.wso2.carbon.apimgt.hostobjects.APIProviderHostObject.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.apimgt.hostobjects.APIProviderHostObject.java

Source

/*
*  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.carbon.apimgt.hostobjects;

import io.swagger.models.Operation;
import io.swagger.models.Path;
import io.swagger.models.Swagger;
import io.swagger.models.auth.SecuritySchemeDefinition;
import io.swagger.parser.SwaggerParser;

import org.apache.axiom.om.OMElement;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ServiceContext;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.woden.WSDLFactory;
import org.apache.woden.WSDLReader;
import org.jaggeryjs.hostobjects.file.FileHostObject;
import org.jaggeryjs.scriptengine.exceptions.ScriptException;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.mozilla.javascript.*;
import org.wso2.carbon.apimgt.api.*;
import org.wso2.carbon.apimgt.api.dto.UserApplicationAPIUsage;
import org.wso2.carbon.apimgt.api.model.*;
import org.wso2.carbon.apimgt.api.model.policy.Policy;
import org.wso2.carbon.apimgt.api.model.policy.PolicyConstants;
import org.wso2.carbon.apimgt.hostobjects.internal.HostObjectComponent;
import org.wso2.carbon.apimgt.hostobjects.internal.ServiceReferenceHolder;
import org.wso2.carbon.apimgt.hostobjects.util.Json;
import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.impl.APIManagerConfiguration;
import org.wso2.carbon.apimgt.impl.APIManagerFactory;
import org.wso2.carbon.apimgt.impl.UserAwareAPIProvider;
import org.wso2.carbon.apimgt.impl.definitions.APIDefinitionFromSwagger20;
import org.wso2.carbon.apimgt.impl.dto.Environment;
import org.wso2.carbon.apimgt.impl.dto.TierPermissionDTO;
import org.wso2.carbon.apimgt.impl.factory.KeyManagerHolder;
import org.wso2.carbon.apimgt.impl.utils.APIAuthenticationAdminClient;
import org.wso2.carbon.apimgt.impl.utils.APIUtil;
import org.wso2.carbon.apimgt.impl.utils.APIVersionComparator;
import org.wso2.carbon.apimgt.impl.utils.APIVersionStringComparator;
import org.wso2.carbon.apimgt.keymgt.client.ProviderKeyMgtClient;
import org.wso2.carbon.apimgt.keymgt.client.SubscriberKeyMgtClient;
import org.wso2.carbon.authenticator.stub.AuthenticationAdminStub;
import org.wso2.carbon.base.ServerConfiguration;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.core.util.PermissionUpdateUtil;
import org.wso2.carbon.governance.lcm.util.CommonUtil;
import org.wso2.carbon.identity.oauth.OAuthAdminService;
import org.wso2.carbon.registry.core.RegistryConstants;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.service.RegistryService;
import org.wso2.carbon.registry.core.session.UserRegistry;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.mgt.stub.UserAdminStub;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;

import javax.cache.Caching;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.xml.namespace.QName;

import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@SuppressWarnings("unused")
public class APIProviderHostObject extends ScriptableObject {

    private static final Log log = LogFactory.getLog(APIProviderHostObject.class);
    //private static Pattern endpointURIPattern=Pattern.compile("^((http(?:s)?:\\/\\/)?([a-zA-Z0-9\\-\\.]{1,})+((\\:([0-9]{1,5}))?)(?:(\\/?|(?:\\/((\\{uri\\.var\\.[\\w]+\\})|[\\w\\-]+)))*)(?:\\/?|\\/\\w+\\.[a-zA-Z0-9]{1,})(?:\\?|(\\?(?:[\\w]+)(?:\\=([\\w\\-]+|\\{uri\\.var\\.[\\w]+\\}))?))?(?:\\&|(\\&(?:[\\w]+)(?:\\=([\\w\\-]+|\\{uri\\.var\\.[\\w]+\\}))?))*)$");
    private static Pattern pathParamExtractorPattern = Pattern.compile("\\{.*?\\}");
    private static Pattern pathParamValidatorPattern = Pattern.compile("\\{uri\\.var\\.[\\w]+\\}");

    private String username;
    private static String VERSION_PARAM = "{version}";
    private static String ICON_PATH = "tmp/icon";

    private APIProvider apiProvider;

    public String getClassName() {
        return "APIProvider";
    }

    // API definitions from swagger v2.0
    static APIDefinition definitionFromSwagger20 = new APIDefinitionFromSwagger20();

    // The zero-argument constructor used for create instances for runtime
    public APIProviderHostObject() throws APIManagementException {

    }

    public APIProviderHostObject(String loggedUser) throws APIManagementException {
        username = loggedUser;
        apiProvider = APIManagerFactory.getInstance().getAPIProvider(loggedUser);
    }

    public String getUsername() {
        return username;
    }

    public static Scriptable jsConstructor(Context cx, Object[] args, Function Obj, boolean inNewExpr)
            throws APIManagementException {

        if (args != null && args.length != 0) {
            String username = (String) args[0];
            return new APIProviderHostObject(username);
        }
        return new APIProviderHostObject();
    }

    public APIProvider getApiProvider() {
        return apiProvider;
    }

    private static APIProvider getAPIProvider(Scriptable thisObj) {
        return ((APIProviderHostObject) thisObj).getApiProvider();
    }

    private static void handleException(String msg) throws APIManagementException {
        log.error(msg);
        throw new APIManagementException(msg);
    }

    private static void handleException(String msg, Throwable t) throws APIManagementException {
        log.error(msg, t);
        throw new APIManagementException(msg, t);
    }

    private static void handleFaultGateWayException(FaultGatewaysException e) throws FaultGatewaysException {
        throw e;
    }

    public static NativeObject jsFunction_login(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {

        if (args == null || args.length == 0 || !isStringValues(args)) {
            handleException("Invalid input parameters to the login method");
        }

        String username = (String) args[0];
        String password = (String) args[1];

        APIManagerConfiguration config = HostObjectComponent.getAPIManagerConfiguration();
        String url = config.getFirstProperty(APIConstants.AUTH_MANAGER_URL);
        if (url == null) {
            handleException("API key manager URL unspecified");
        }

        NativeObject row = new NativeObject();
        try {

            UserAdminStub userAdminStub = new UserAdminStub(url + "UserAdmin");
            CarbonUtils.setBasicAccessSecurityHeaders(username, password, true, userAdminStub._getServiceClient());
            //If multiple user stores are in use, and if the user hasn't specified the domain to which
            //he needs to login to
            /* Below condition is commented out as per new multiple users-store implementation,users from
            different user-stores not needed to input domain names when tried to login,APIMANAGER-1392*/
            // if (userAdminStub.hasMultipleUserStores() && !username.contains("/")) {
            //      handleException("Domain not specified. Please provide your username as domain/username");
            // }
        } catch (Exception e) {
            log.error("Error occurred while checking for multiple user stores", e);
        }

        boolean isTenantFlowStarted = false;
        try {
            AuthenticationAdminStub authAdminStub = new AuthenticationAdminStub(null, url + "AuthenticationAdmin");
            ServiceClient client = authAdminStub._getServiceClient();
            Options options = client.getOptions();
            options.setManageSession(true);

            String tenantDomain = MultitenantUtils.getTenantDomain(username);
            //update permission cache before validate user
            int tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                    .getTenantId(tenantDomain);
            if (tenantId == MultitenantConstants.INVALID_TENANT_ID) {
                handleException("Invalid tenant domain.");
            }
            PermissionUpdateUtil.updatePermissionTree(tenantId);

            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            RegistryService registryService = ServiceReferenceHolder.getInstance().getRegistryService();
            CommonUtil.addDefaultLifecyclesIfNotAvailable(registryService.getConfigSystemRegistry(tenantId),
                    CommonUtil.getRootSystemRegistry(tenantId));

            String host = new URL(url).getHost();
            if (!authAdminStub.login(username, password, host)) {
                handleException("Login failed. Please recheck the username and password and try again..");
            }
            ServiceContext serviceContext = authAdminStub._getServiceClient().getLastOperationContext()
                    .getServiceContext();
            String sessionCookie = (String) serviceContext.getProperty(HTTPConstants.COOKIE_STRING);

            String usernameWithDomain = APIUtil.getLoggedInUserInfo(sessionCookie, url).getUserName();
            usernameWithDomain = APIUtil.setDomainNameToUppercase(usernameWithDomain);
            boolean isSuperTenant = false;

            if (tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) {
                isSuperTenant = true;
            } else {
                usernameWithDomain = usernameWithDomain + "@" + tenantDomain;
            }
            boolean authorized = APIUtil.checkPermissionQuietly(usernameWithDomain,
                    APIConstants.Permissions.API_CREATE)
                    || APIUtil.checkPermissionQuietly(usernameWithDomain, APIConstants.Permissions.API_PUBLISH);

            boolean displayStoreUrlFromPublisher = false;
            if (config != null) {
                displayStoreUrlFromPublisher = Boolean
                        .parseBoolean(config.getFirstProperty(APIConstants.SHOW_API_STORE_URL_FROM_PUBLISHER));
            }
            if (authorized) {

                row.put("user", row, usernameWithDomain);
                row.put("sessionId", row, sessionCookie);
                row.put("isSuperTenant", row, isSuperTenant);
                row.put("error", row, false);
                row.put("showStoreURL", row, displayStoreUrlFromPublisher);
            } else {
                handleException("Login failed. Insufficient privileges.");
            }
        } catch (Exception e) {
            row.put("error", row, true);
            row.put("detail", row, e.getMessage());
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }

        return row;
    }

    /**
     * This method is used to update the permission cache from jaggery side. user name should be passed as a parameter
     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return true if update successful, false otherwise
     * @throws APIManagementException
     */
    public static boolean jsFunction_updatePermissionCache(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        if (args == null || args.length == 0) {
            handleException("Invalid input parameters to the login method");
        }
        String username = (String) args[0];
        boolean updated = false;
        try {

            APIUtil.updatePermissionCache(username);
            updated = true;
        } catch (Exception e) {
            // If the user creation or permission change done in another node in distributed setup, users may not be
            // able to login into the system using SSO until permission cache updated. We call this method internally
            // to update the permission cache, when user trying to login into the system. If this request fails user
            // may not able to login into the systems and user will be getting an invalid credentials message. User
            // can login into the system once permission cache automatically updated in predefined interval.
            log.error("Error while updating permissions for user " + username, e);
        }
        return updated;
    }

    public static String jsFunction_getAuthServerURL(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {

        APIManagerConfiguration config = HostObjectComponent.getAPIManagerConfiguration();
        String url = config.getFirstProperty(APIConstants.AUTH_MANAGER_URL);
        if (url == null) {
            handleException("API key manager URL unspecified");
        }
        return url;
    }

    public static String jsFunction_getHTTPsURL(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {
        String hostName = CarbonUtils.getServerConfiguration().getFirstProperty("HostName");
        String backendHttpsPort = HostObjectUtils.getBackendPort("https");
        if (hostName == null) {
            hostName = System.getProperty("carbon.local.ip");
        }
        return "https://" + hostName + ":" + backendHttpsPort;

    }

    /**
     * This method is to functionality of managing an API in API-Provider     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return true if the API was added successfully
     * @throws APIManagementException Wrapped exception by org.wso2.carbon.apimgt.api.APIManagementException
     */
    public static boolean jsFunction_manageAPI(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException, ScriptException, FaultGatewaysException {
        boolean success = false;

        if (args == null || args.length == 0) {
            handleException("Invalid number of input parameters.");
        }

        NativeObject apiData = (NativeObject) args[0];
        String provider = String.valueOf(apiData.get("provider", apiData));
        String name = (String) apiData.get("apiName", apiData);
        String version = (String) apiData.get("version", apiData);

        String subscriptionAvailability = (String) apiData.get("subscriptionAvailability", apiData);
        String subscriptionAvailableTenants = "";
        if (subscriptionAvailability != null
                && subscriptionAvailability.equals(APIConstants.SUBSCRIPTION_TO_SPECIFIC_TENANTS)) {
            subscriptionAvailableTenants = (String) apiData.get("subscriptionTenants", apiData);
        }

        String defaultVersion = (String) apiData.get("defaultVersion", apiData);
        String transport = getTransports(apiData);

        String tier = (String) apiData.get("tier", apiData);
        String apiLevelPolicy = null;
        if (APIUtil.isAdvanceThrottlingEnabled()) {
            apiLevelPolicy = (String) apiData.get("apiPolicy", apiData);
        }
        String businessOwner = (String) apiData.get("bizOwner", apiData);
        String businessOwnerEmail = (String) apiData.get("bizOwnerMail", apiData);
        String technicalOwner = (String) apiData.get("techOwner", apiData);
        String technicalOwnerEmail = (String) apiData.get("techOwnerMail", apiData);
        String environments = (String) apiData.get("environments", apiData);
        String responseCache = (String) apiData.get("responseCache", apiData);
        String corsConfiguraion = (String) apiData.get("corsConfiguration", apiData);

        int cacheTimeOut = APIConstants.API_RESPONSE_CACHE_TIMEOUT;
        if (APIConstants.ENABLED.equalsIgnoreCase(responseCache)) {
            responseCache = APIConstants.ENABLED;
            try {
                cacheTimeOut = Integer.parseInt((String) apiData.get("cacheTimeout", apiData));
            } catch (NumberFormatException e) {
                //ignore
            }
        } else {
            responseCache = APIConstants.DISABLED;
        }

        if (provider != null) {
            provider = APIUtil.replaceEmailDomain(provider);
        }
        provider = (provider != null ? provider.trim() : null);
        name = (name != null ? name.trim() : null);
        version = (version != null ? version.trim() : null);

        APIIdentifier apiId = new APIIdentifier(provider, name, version);
        APIProvider apiProvider = getAPIProvider(thisObj);
        API api = null;
        boolean isTenantFlowStarted = false;
        String tenantDomain = null;
        try {
            tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(provider));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            api = apiProvider.getAPI(apiId);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }

        api.setTransports(transport);
        api.setSubscriptionAvailability(subscriptionAvailability);
        api.setSubscriptionAvailableTenants(subscriptionAvailableTenants);
        api.setResponseCache(responseCache);
        api.setCacheTimeout(cacheTimeOut);
        api.setAsDefaultVersion("default_version".equals(defaultVersion));

        String productionTps = (String) apiData.get("productionTps", apiData);
        String sandboxTps = (String) apiData.get("sandboxTps", apiData);

        if (!"none".equals(productionTps)) {
            api.setProductionMaxTps(productionTps);
        }

        if (!"none".equals(sandboxTps)) {
            api.setSandboxMaxTps(sandboxTps);
        }

        if (!"none".equals(businessOwner)) {
            api.setBusinessOwner(businessOwner);
        }
        if (!"none".equals(businessOwnerEmail)) {
            api.setBusinessOwnerEmail(businessOwnerEmail);
        }
        if (!"none".equals(technicalOwner)) {
            api.setTechnicalOwner(technicalOwner);
        }
        if (!"none".equals(technicalOwnerEmail)) {
            api.setTechnicalOwnerEmail(technicalOwnerEmail);
        }
        api.setEnvironments(APIUtil.extractEnvironmentsForAPI(environments));

        CORSConfiguration corsConfiguration = APIUtil.getCorsConfigurationDtoFromJson(corsConfiguraion);
        if (corsConfiguration != null) {
            api.setCorsConfiguration(corsConfiguration);
        }
        Set<Tier> availableTier = new HashSet<Tier>();
        String[] tierNames;
        if (tier != null) {
            tierNames = tier.split(",");
            for (String tierName : tierNames) {
                availableTier.add(new Tier(tierName));
            }
            api.removeAllTiers();
            api.addAvailableTiers(availableTier);
        }

        if (apiLevelPolicy != null) {
            if ("none".equals(apiLevelPolicy)) {
                api.setApiLevelPolicy(null);
            } else {
                api.setApiLevelPolicy(apiLevelPolicy);
            }
        } else {
            api.setApiLevelPolicy(null);
        }

        api.setLastUpdated(new Date());

        if (apiData.get("swagger", apiData) != null) {

            //Read URI Templates from swagger resource and set to api object
            Set<URITemplate> uriTemplates = definitionFromSwagger20.getURITemplates(api,
                    String.valueOf(apiData.get("swagger", apiData)));
            api.setUriTemplates(uriTemplates);

            //scopes
            Set<Scope> scopes = definitionFromSwagger20.getScopes(String.valueOf(apiData.get("swagger", apiData)));
            api.setScopes(scopes);

            try {
                int tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                        .getTenantId(tenantDomain);
                for (URITemplate uriTemplate : uriTemplates) {
                    Scope scope = uriTemplate.getScope();
                    if (scope != null && !(APIUtil.isWhiteListedScope(scope.getKey()))) {
                        if (apiProvider.isScopeKeyAssigned(apiId, scope.getKey(), tenantId)) {
                            handleException("Scope " + scope.getKey() + " is already assigned by another API");
                        }
                    }
                }
            } catch (UserStoreException e) {
                handleException("Error while reading tenant information ", e);
            }

            //Save swagger in the registry
            apiProvider.saveSwagger20Definition(api.getId(), (String) apiData.get("swagger", apiData));
        }

        // removing scopes from cache
        try {
            ProviderKeyMgtClient providerClient = HostObjectUtils.getProviderClient();
            String[] consumerKeys = apiProvider.getConsumerKeys(new APIIdentifier(provider, name, version));
            if (consumerKeys != null && consumerKeys.length != 0) {
                providerClient.removeScopeCache(consumerKeys);
            }

        } catch (APIManagementException e) {
            //swallowing the excepion since the api update should happen even if cache update fails
            log.error("Error while removing the scope cache", e);
        }
        //get new key manager instance for  resource registration.
        KeyManager keyManager = KeyManagerHolder.getKeyManagerInstance();

        Map registeredResource = keyManager.getResourceByApiId(api.getId().toString());

        if (registeredResource == null) {
            boolean isNewResourceRegistered = keyManager.registerNewResource(api, null);
            if (!isNewResourceRegistered) {
                handleException("APIResource registration is failed while adding the API- "
                        + api.getId().getApiName() + "-" + api.getId().getVersion());
            }
        } else {
            //update APIResource.
            String resourceId = (String) registeredResource.get("resourceId");
            if (resourceId == null) {
                handleException("APIResource update is failed because of empty resourceID.");
            }
            keyManager.updateRegisteredResource(api, registeredResource);
        }
        return saveAPI(apiProvider, api, null, false);
    }

    /**
     * This method is to functionality of update implementation of an API in API-Provider     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return true if the API was added successfully
     * @throws APIManagementException Wrapped exception by org.wso2.carbon.apimgt.api.APIManagementException
     */
    public static boolean jsFunction_updateAPIImplementation(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException, ScriptException, FaultGatewaysException {

        // Get the InSeq or outSeq here and put into registry

        if (args == null || args.length == 0) {
            handleException("Invalid number of input parameters.");
        }

        NativeObject apiData = (NativeObject) args[0];
        String provider = String.valueOf(apiData.get("provider", apiData));
        String name = (String) apiData.get("apiName", apiData);
        String version = (String) apiData.get("version", apiData);
        String implementationType = (String) apiData.get("implementation_type", apiData);
        String corsConfiguraion = (String) apiData.get("corsConfiguration", apiData);
        if (provider != null) {
            provider = APIUtil.replaceEmailDomain(provider);
        }
        provider = (provider != null ? provider.trim() : null);
        name = (name != null ? name.trim() : null);
        version = (version != null ? version.trim() : null);

        APIIdentifier apiId = new APIIdentifier(provider, name, version);
        APIProvider apiProvider = getAPIProvider(thisObj);
        API api = null;
        boolean isTenantFlowStarted = false;
        String tenantDomain;
        try {
            tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(provider));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            api = apiProvider.getAPI(apiId);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }

        api.setLastUpdated(new Date());

        String wsdl = (String) apiData.get("wsdl", apiData);
        String wadl = (String) apiData.get("wadl", apiData);
        String endpointSecured = (String) apiData.get("endpointSecured", apiData);
        String endpointAuthDigest = (String) apiData.get("endpointAuthDigest", apiData);
        String endpointUTUsername = (String) apiData.get("endpointUTUsername", apiData);
        String endpointUTPassword = (String) apiData.get("endpointUTPassword", apiData);

        api.setWadlUrl(wadl);
        if (wsdl != null && !wsdl.isEmpty()) {
            api.setWsdlUrl(wsdl);
        }
        api.setEndpointConfig((String) apiData.get("endpoint_config", apiData));

        if (implementationType.equalsIgnoreCase(APIConstants.IMPLEMENTATION_TYPE_INLINE)) {
            api.setImplementation(APIConstants.IMPLEMENTATION_TYPE_INLINE);
        } else if (implementationType.equalsIgnoreCase(APIConstants.IMPLEMENTATION_TYPE_ENDPOINT)) {
            api.setImplementation(APIConstants.IMPLEMENTATION_TYPE_ENDPOINT);
            // Validate endpoint URI format
            validateEndpointURI(api.getEndpointConfig());
        } else {
            throw new APIManagementException("Invalid Implementation Type.");
        }

        //set secured endpoint parameters
        if ("secured".equals(endpointSecured)) {
            api.setEndpointSecured(true);
            api.setEndpointUTUsername(endpointUTUsername);
            api.setEndpointUTPassword(endpointUTPassword);
            if ("digestAuth".equals(endpointAuthDigest)) {
                api.setEndpointAuthDigest(true);
            } else {
                api.setEndpointAuthDigest(false);
            }
        } else {
            api.setEndpointSecured(false);
            api.setEndpointAuthDigest(false);
            api.setEndpointUTUsername(null);
            api.setEndpointUTPassword(null);
        }

        if (apiData.get("swagger", apiData) != null) {
            //Read swagger from the registry todo: check why was this done
            //String swaggerFromRegistry = apiProvider.getSwagger20Definition(api.getId());

            //Read URI Templates from swagger resource and set to api object
            Set<URITemplate> uriTemplates = definitionFromSwagger20.getURITemplates(api,
                    (String) apiData.get("swagger", apiData));
            api.setUriTemplates(uriTemplates);

            apiProvider.saveSwagger20Definition(api.getId(), (String) apiData.get("swagger", apiData));
        }

        String inSequence = (String) apiData.get("inSequence", apiData);
        String outSequence = (String) apiData.get("outSequence", apiData);
        String faultSequence = (String) apiData.get("faultSequence", apiData);

        api.removeCustomSequences();

        if (!"none".equals(inSequence)) {
            api.setInSequence(inSequence);
        }

        if (!"none".equals(outSequence)) {
            api.setOutSequence(outSequence);
        }

        if (!"none".equals(faultSequence)) {
            api.setFaultSequence(faultSequence);
        }

        CORSConfiguration corsConfiguration = APIUtil.getCorsConfigurationDtoFromJson(corsConfiguraion);
        if (corsConfiguration != null) {
            api.setCorsConfiguration(corsConfiguration);
        }
        return saveAPI(apiProvider, api, null, false);

    }

    private static String uploadSequenceFile(APIProvider apiProvider, FileHostObject seqFile, String filePath)
            throws APIManagementException, ScriptException {
        ResourceFile inSeq = new ResourceFile(seqFile.getInputStream(),
                seqFile.getJavaScriptFile().getContentType());
        String seqFileName;
        try {
            OMElement seqElment = APIUtil.buildOMElement(seqFile.getInputStream());
            seqFileName = seqElment.getAttributeValue(new QName("name"));
        } catch (Exception e) {
            String errorMsg = "An Error has occurred while reading custom sequence file";
            log.error(errorMsg, e);
            throw new APIManagementException(errorMsg, e);
        }
        apiProvider.addResourceFile(filePath + seqFileName, inSeq);
        return seqFileName;
    }

    /**
     * This method is to functionality of uploading sequence to the registry     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return true if the sequence was uploaded successfully
     * @throws APIManagementException Wrapped exception by org.wso2.carbon.apimgt.api.APIManagementException
     */
    public static String jsFunction_uploadSequenceFile(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException, ScriptException {

        if (args == null || args.length == 0) {
            handleException("Invalid number of input parameters.");
        }

        String inSeqFileName = null;

        NativeObject apiData = (NativeObject) args[0];
        String provider = String.valueOf(apiData.get("provider", apiData));
        String name = (String) apiData.get("apiName", apiData);
        String version = (String) apiData.get("version", apiData);
        String sequenceType = (String) apiData.get("seqType", apiData);
        if (provider != null) {
            provider = APIUtil.replaceEmailDomain(provider);
        }
        provider = (provider != null ? provider.trim() : null);
        name = (name != null ? name.trim() : null);
        version = (version != null ? version.trim() : null);

        APIIdentifier apiId = new APIIdentifier(provider, name, version);

        APIProvider apiProvider = getAPIProvider(thisObj);
        if (apiData.get("seqFile", apiData) != null) {
            FileHostObject seqFile = (FileHostObject) apiData.get("seqFile", apiData);
            String inSeqPath = APIUtil.getSequencePath(apiId, sequenceType) + RegistryConstants.PATH_SEPARATOR;
            inSeqFileName = uploadSequenceFile(apiProvider, seqFile, inSeqPath);
        }
        return inSeqFileName;

    }

    public static boolean jsFunction_isAPIUpdateValid(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException, ScriptException, FaultGatewaysException {

        if (args == null || args.length == 0) {
            handleException("Invalid number of input parameters.");
        }

        boolean success = false;

        NativeObject apiData = (NativeObject) args[0];
        String provider = String.valueOf(apiData.get("provider", apiData));
        String name = (String) apiData.get("apiName", apiData);
        String version = (String) apiData.get("version", apiData);

        if (provider != null) {
            provider = APIUtil.replaceEmailDomain(provider);
        }
        provider = (provider != null ? provider.trim() : null);
        name = (name != null ? name.trim() : null);
        version = (version != null ? version.trim() : null);
        APIIdentifier apiId = new APIIdentifier(provider, name, version);
        APIProvider apiProvider = getAPIProvider(thisObj);
        API api = null;
        boolean isTenantFlowStarted = false;
        String tenantDomain;
        try {
            tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(provider));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            api = apiProvider.getAPI(apiId);
            success = apiProvider.isAPIUpdateValid(api);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }

        return success;
    }

    /**
     * This method is to functionality of update design API in API-Provider     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return true if the API was added successfully
     * @throws APIManagementException Wrapped exception by org.wso2.carbon.apimgt.api.APIManagementException
     */
    public static boolean jsFunction_updateAPIDesign(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException, ScriptException, FaultGatewaysException {

        if (args == null || args.length == 0) {
            handleException("Invalid number of input parameters.");
        }

        boolean success = false;

        NativeObject apiData = (NativeObject) args[0];
        String provider = String.valueOf(apiData.get("provider", apiData));
        String name = (String) apiData.get("apiName", apiData);
        String version = (String) apiData.get("version", apiData);
        FileHostObject fileHostObject = (FileHostObject) apiData.get("imageUrl", apiData);
        //        String contextVal = (String) apiData.get("context", apiData);
        String description = (String) apiData.get("description", apiData);

        /* Business Information*/
        String techOwner = (String) apiData.get("techOwner", apiData);
        String techOwnerEmail = (String) apiData.get("techOwnerEmail", apiData);
        String bizOwner = (String) apiData.get("bizOwner", apiData);
        String bizOwnerEmail = (String) apiData.get("bizOwnerEmail", apiData);

        //        String context = contextVal.startsWith("/") ? contextVal : ("/" + contextVal);
        //        String providerDomain = MultitenantUtils.getTenantDomain(provider);

        //TODO: check and remove
        /*  if(!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equalsIgnoreCase(providerDomain)) {
        //Create tenant aware context for API
        context= "/t/"+ providerDomain+context;
          }*/

        String tags = (String) apiData.get("tags", apiData);
        Set<String> tag = new HashSet<String>();

        if (tags != null) {
            if (tags.contains(",")) {
                String[] userTag = tags.split(",");
                tag.addAll(Arrays.asList(userTag).subList(0, tags.split(",").length));
            } else {
                tag.add(tags);
            }
        }

        String visibility = (String) apiData.get("visibility", apiData);
        String visibleRoles = "";

        if (visibility != null && visibility.equals(APIConstants.API_RESTRICTED_VISIBILITY)) {
            visibleRoles = (String) apiData.get("visibleRoles", apiData);
        }

        if (provider != null) {
            provider = APIUtil.replaceEmailDomain(provider);
        }
        provider = (provider != null ? provider.trim() : null);
        name = (name != null ? name.trim() : null);
        version = (version != null ? version.trim() : null);
        APIIdentifier apiId = new APIIdentifier(provider, name, version);
        APIProvider apiProvider = getAPIProvider(thisObj);
        API api = null;
        boolean isTenantFlowStarted = false;
        String tenantDomain;
        try {
            tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(provider));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            api = apiProvider.getAPI(apiId);
            boolean isValid = apiProvider.isAPIUpdateValid(api);
            if (!isValid) {
                throw new APIManagementException(" User doesn't have permission for update");
            }
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        if (apiData.containsKey("wsdl")) {
            String wsdl = (String) apiData.get("wsdl", apiData);
            if (StringUtils.isNotEmpty(wsdl)) {
                api.setWsdlUrl(wsdl);
            }
        }

        if (apiData.get("swagger", apiData) != null) {
            // Read URI Templates from swagger resource and set it to api object
            Set<URITemplate> uriTemplates = definitionFromSwagger20.getURITemplates(api,
                    (String) apiData.get("swagger", apiData));
            api.setUriTemplates(uriTemplates);

            // Save the swagger definition in the registry
            apiProvider.saveSwagger20Definition(api.getId(), (String) apiData.get("swagger", apiData));
        }

        api.setDescription(StringEscapeUtils.escapeHtml(description));
        HashSet<String> deletedTags = new HashSet<String>(api.getTags());
        deletedTags.removeAll(tag);
        api.removeTags(deletedTags);
        api.addTags(tag);
        api.setBusinessOwner(bizOwner);
        api.setBusinessOwnerEmail(bizOwnerEmail);
        api.setTechnicalOwner(techOwner);
        api.setTechnicalOwnerEmail(techOwnerEmail);
        api.setVisibility(visibility);
        api.setVisibleRoles(visibleRoles != null ? visibleRoles.trim() : null);
        api.setLastUpdated(new Date());

        return saveAPI(apiProvider, api, fileHostObject, false);
    }

    /**
     * This method is to functionality of create a new API in API-Provider     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return true if the API was added successfully
     * @throws APIManagementException Wrapped exception by org.wso2.carbon.apimgt.api.APIManagementException
     */
    public static boolean jsFunction_createAPI(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException, ScriptException, FaultGatewaysException {

        if (args == null || args.length == 0) {
            handleException("Invalid number of input parameters.");
        }

        NativeObject apiData = (NativeObject) args[0];

        String provider = String.valueOf(apiData.get("provider", apiData));
        String name = (String) apiData.get("apiName", apiData);
        String version = (String) apiData.get("version", apiData);
        String contextVal = (String) apiData.get("context", apiData);

        String providerDomain = MultitenantUtils.getTenantDomain(provider);

        String context = contextVal.startsWith("/") ? contextVal : ("/" + contextVal);
        if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equalsIgnoreCase(providerDomain)) {
            //Create tenant aware context for API
            context = "/t/" + providerDomain + context;
        }

        if (provider != null) {
            provider = APIUtil.replaceEmailDomain(provider);
        }
        provider = (provider != null ? provider.trim() : null);
        name = (name != null ? name.trim() : null);
        version = (version != null ? version.trim() : null);

        APIIdentifier apiId = new APIIdentifier(provider, name, version);
        APIProvider apiProvider = getAPIProvider(thisObj);

        if (apiProvider.isAPIAvailable(apiId)) {
            handleException("Error occurred while adding the API. A duplicate API already exists for " + name + "-"
                    + version);
        }

        API api = new API(apiId);
        api.setStatus(APIStatus.CREATED);

        // This is to support the new Pluggable version strategy
        // if the context does not contain any {version} segment, we use the default version strategy.
        context = checkAndSetVersionParam(context);
        api.setContextTemplate(context);

        context = updateContextWithVersion(version, contextVal, context);

        api.setContext(context);
        api.setVisibility(APIConstants.API_GLOBAL_VISIBILITY);
        api.setLastUpdated(new Date());

        return saveAPI(apiProvider, api, null, true);
    }

    /**
     * Returns the Swagger12 definition //todo this actually returns swagger v2.0, create a new method
     * @param cx
     * @param thisObj
     * @param args
     * @param funObj
     * @return
     * @throws APIManagementException
     * @throws ScriptException
     */
    public static NativeObject jsFunction_getSwagger12Resource(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException, ScriptException {
        if (args == null || args.length == 0) {
            handleException("Invalid number of input parameters.");
        }

        NativeObject apiData = (NativeObject) args[0];
        String provider = String.valueOf(apiData.get("provider", apiData));
        String name = (String) apiData.get("apiName", apiData);
        String version = (String) apiData.get("version", apiData);

        if (provider != null) {
            provider = APIUtil.replaceEmailDomain(provider);
        }
        provider = (provider != null ? provider.trim() : null);
        name = (name != null ? name.trim() : null);
        version = (version != null ? version.trim() : null);
        APIIdentifier apiId = new APIIdentifier(provider, name, version);
        //        APIProvider apiProvider = getAPIProvider(thisObj);

        boolean isTenantFlowStarted = false;
        String apiJSON = null;
        try {
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(provider));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            RegistryService registryService = ServiceReferenceHolder.getInstance().getRegistryService();
            int tenantId;
            UserRegistry registry;
            try {
                tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                        .getTenantId(tenantDomain);
                registry = registryService.getGovernanceSystemRegistry(tenantId);

                apiJSON = definitionFromSwagger20.getAPIDefinition(apiId, registry); //apiProvider.getSwagger12Definition(apiId);
            } catch (RegistryException e) {
                handleException("Error when create registry instance ", e);
            } catch (UserStoreException e) {
                handleException("Error while reading tenant information ", e);
            }
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }

        NativeObject row = new NativeObject();

        row.put("swagger", row, apiJSON);

        return row;
    }

    /**
     * This method save or update the API object
     * @param apiProvider
     * @param api
     * @param fileHostObject
     * @param isNewApi
     * @return true if the API was added successfully
     * @throws APIManagementException
     */
    private static boolean saveAPI(APIProvider apiProvider, API api, FileHostObject fileHostObject,
            boolean isNewApi) throws APIManagementException, FaultGatewaysException {
        boolean success = false;
        boolean isTenantFlowStarted = false;
        try {
            String tenantDomain = MultitenantUtils
                    .getTenantDomain(APIUtil.replaceEmailDomainBack(api.getId().getProviderName()));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            if (fileHostObject != null && fileHostObject.getJavaScriptFile().getLength() != 0) {

                String thumbPath = addThumbIcon(fileHostObject.getInputStream(),
                        fileHostObject.getJavaScriptFile().getContentType(), apiProvider, api);
            }
            if (isNewApi) {
                apiProvider.addAPI(api);
            } else {
                apiProvider.manageAPI(api);
            }
            success = true;
        } catch (ScriptException e) {
            handleException(
                    "Error while adding the API- " + api.getId().getApiName() + "-" + api.getId().getVersion(), e);
            return false;
        } catch (FaultGatewaysException e) {
            handleFaultGateWayException(e);
            return false;
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }

        return success;
    }

    /**
     * This method is to functionality of add a new API in API-Provider
     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return true if the API was added successfully
     * @throws APIManagementException Wrapped exception by org.wso2.carbon.apimgt.api.APIManagementException
     * @throws FaultGatewaysException
     */
    public static boolean jsFunction_addAPI(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException, ScriptException, FaultGatewaysException {
        if (args == null || args.length == 0) {
            handleException("Invalid number of input parameters.");
        }

        boolean success;
        NativeObject apiData = (NativeObject) args[0];
        String provider = String.valueOf(apiData.get("provider", apiData));
        if (provider != null) {
            provider = APIUtil.replaceEmailDomain(provider);
        }

        String name = (String) apiData.get("apiName", apiData);
        String version = (String) apiData.get("version", apiData);
        String defaultVersion = (String) apiData.get("defaultVersion", apiData);
        String description = (String) apiData.get("description", apiData);
        String endpoint = (String) apiData.get("endpoint", apiData);
        String sandboxUrl = (String) apiData.get("sandbox", apiData);
        String visibility = (String) apiData.get("visibility", apiData);
        String thumbUrl = (String) apiData.get("thumbUrl", apiData);
        String environments = (String) apiData.get("environments", apiData);
        String visibleRoles = "";

        if (name != null) {
            name = name.trim();
            if (name.isEmpty()) {
                handleException("API name is not specified");
            }
        }

        if (version != null) {
            version = version.trim();
            if (version.isEmpty()) {
                handleException("Version not specified for API " + name);
            }
        }

        if (visibility != null && visibility.equals(APIConstants.API_RESTRICTED_VISIBILITY)) {
            visibleRoles = (String) apiData.get("visibleRoles", apiData);
        }

        if (sandboxUrl != null && sandboxUrl.trim().length() == 0) {
            sandboxUrl = null;
        }

        if (endpoint != null && endpoint.trim().length() == 0) {
            endpoint = null;
        }

        if (endpoint != null && !endpoint.startsWith("http") && !endpoint.startsWith("https")) {
            endpoint = "http://" + endpoint;
        }
        if (sandboxUrl != null && !sandboxUrl.startsWith("http") && !sandboxUrl.startsWith("https")) {
            sandboxUrl = "http://" + sandboxUrl;
        }

        String redirectURL = (String) apiData.get("redirectURL", apiData);
        boolean advertiseOnly = Boolean.parseBoolean((String) apiData.get("advertiseOnly", apiData));
        String apiOwner = (String) apiData.get("apiOwner", apiData);

        if (apiOwner == null || apiOwner.equals("")) {
            apiOwner = provider;
        }

        String wsdl = (String) apiData.get("wsdl", apiData);
        String wadl = (String) apiData.get("wadl", apiData);
        String tags = (String) apiData.get("tags", apiData);

        String subscriptionAvailability = (String) apiData.get("subscriptionAvailability", apiData);
        String subscriptionAvailableTenants = "";
        if (subscriptionAvailability != null
                && subscriptionAvailability.equals(APIConstants.SUBSCRIPTION_TO_SPECIFIC_TENANTS)) {
            subscriptionAvailableTenants = (String) apiData.get("subscriptionTenants", apiData);
        }

        Set<String> tag = new HashSet<String>();

        if (tags != null) {
            if (tags.contains(",")) {
                String[] userTag = tags.split(",");
                tag.addAll(Arrays.asList(userTag).subList(0, tags.split(",").length));
            } else {
                tag.add(tags);
            }
        }

        String transport = getTransports(apiData);

        String tier = (String) apiData.get("tier", apiData);
        if (StringUtils.isBlank(tier)) {
            handleException("No tier defined for the API");
        }
        FileHostObject fileHostObject = (FileHostObject) apiData.get("imageUrl", apiData);
        String contextVal = (String) apiData.get("context", apiData);

        if (contextVal.isEmpty()) {
            handleException("Context not defined for API");
        }

        if (contextVal.endsWith("/")) {
            handleException("Context cannot end with '/' character");
        }

        APIProvider apiProvider = getAPIProvider(thisObj);
        //check for context exists
        if (apiProvider.isDuplicateContextTemplate(contextVal)) {
            handleException("Error occurred while adding the API. A duplicate API context already exists for "
                    + contextVal);
        }
        String context = contextVal.startsWith("/") ? contextVal : ("/" + contextVal);
        String providerDomain = MultitenantUtils.getTenantDomain(String.valueOf(apiData.get("provider", apiData)));
        if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equalsIgnoreCase(providerDomain)) {
            //Create tenant aware context for API
            context = "/t/" + providerDomain + context;
        }

        // This is to support the new Pluggable version strategy
        // if the context does not contain any {version} segment, we use the default version strategy.
        context = checkAndSetVersionParam(context);

        String contextTemplate = context;
        context = updateContextWithVersion(version, contextVal, context);

        NativeArray uriTemplateArr = (NativeArray) apiData.get("uriTemplateArr", apiData);

        String techOwner = (String) apiData.get("techOwner", apiData);
        String techOwnerEmail = (String) apiData.get("techOwnerEmail", apiData);
        String bizOwner = (String) apiData.get("bizOwner", apiData);
        String bizOwnerEmail = (String) apiData.get("bizOwnerEmail", apiData);

        String endpointSecured = (String) apiData.get("endpointSecured", apiData);
        String endpointAuthDigest = (String) apiData.get("endpointAuthDigest", apiData);
        String endpointUTUsername = (String) apiData.get("endpointUTUsername", apiData);
        String endpointUTPassword = (String) apiData.get("endpointUTPassword", apiData);

        String inSequence = (String) apiData.get("inSequence", apiData);
        String outSequence = (String) apiData.get("outSequence", apiData);
        String faultSequence = (String) apiData.get("faultSequence", apiData);

        String responseCache = (String) apiData.get("responseCache", apiData);
        String corsConfiguraion = (String) apiData.get("corsConfiguration", apiData);

        int cacheTimeOut = APIConstants.API_RESPONSE_CACHE_TIMEOUT;
        if (APIConstants.ENABLED.equalsIgnoreCase(responseCache)) {
            responseCache = APIConstants.ENABLED;
            try {
                cacheTimeOut = Integer.parseInt((String) apiData.get("cacheTimeout", apiData));
            } catch (NumberFormatException e) {
                //ignore
            }
        } else {
            responseCache = APIConstants.DISABLED;
        }

        provider = (provider != null ? provider.trim() : null);
        name = (name != null ? name.trim() : null);
        version = (version != null ? version.trim() : null);
        APIIdentifier apiId = new APIIdentifier(provider, name, version);

        if (apiProvider.isAPIAvailable(apiId)) {
            handleException("Error occurred while adding the API. A duplicate API already exists for " + name + "-"
                    + version);
        }

        API api = new API(apiId);

        // to keep the backword compatibility if swagger not set process from
        // resource_config or old way.
        if (apiData.get("swagger", apiData) == null) {
            if (apiData.get("resource_config", apiData) != null) {
                Set<URITemplate> uriTemplates = new LinkedHashSet<URITemplate>();
                JSONParser parser = new JSONParser();
                JSONObject resourceConfig = null;

                try {
                    resourceConfig = (JSONObject) parser.parse((String) apiData.get("resource_config", apiData));
                } catch (ParseException e) {
                    handleException("Invalid resource config", e);
                } catch (ClassCastException e) {
                    handleException("Unable to create JSON object from resource config", e);
                }

                // process scopes
                JSONArray scopes = (JSONArray) resourceConfig.get("scopes");
                Set<Scope> scopeList = new LinkedHashSet<Scope>();
                for (int i = 0; i < scopes.size(); i++) {
                    Map scope = (Map) scopes.get(i); // access with get() method
                    Scope scopeObj = new Scope();
                    scopeObj.setKey((String) scope.get("key"));
                    scopeObj.setName((String) scope.get("name"));
                    scopeObj.setRoles((String) scope.get("roles"));
                    scopeObj.setDescription((String) scope.get("description"));
                    scopeList.add(scopeObj);
                }
                api.setScopes(scopeList);

                JSONArray resources = (JSONArray) resourceConfig.get("resources");
                for (int k = 0; k < resources.size(); k++) {
                    JSONObject resource = (JSONObject) resources.get(k);

                    Map http_verbs = (Map) resource.get("http_verbs");
                    Iterator iterator = http_verbs.entrySet().iterator();

                    while (iterator.hasNext()) {
                        Map.Entry mapEntry = (Map.Entry) iterator.next();
                        Map mapEntryValue = (Map) mapEntry.getValue();

                        URITemplate template = new URITemplate();
                        String uriTempVal = (String) resource.get("url_pattern");
                        uriTempVal = uriTempVal.startsWith("/") ? uriTempVal : ("/" + uriTempVal);
                        template.setUriTemplate(uriTempVal);
                        String verb = (String) mapEntry.getKey();
                        if (isHTTPMethodValid(verb)) {
                            template.setHTTPVerb(verb);
                        } else {
                            handleException("Specified HTTP verb " + verb + " is invalid");
                        }

                        String authType = (String) mapEntryValue.get("auth_type");
                        if (authType.equals("Application & Application User")) {
                            authType = APIConstants.AUTH_APPLICATION_OR_USER_LEVEL_TOKEN;
                        }
                        if (authType.equals("Application User")) {
                            authType = "Application_User";
                        }
                        if (authType.equals("Application")) {
                            authType = APIConstants.AUTH_APPLICATION_LEVEL_TOKEN;
                        }
                        template.setThrottlingTier((String) mapEntryValue.get("throttling_tier"));
                        template.setAuthType(authType);
                        template.setResourceURI(endpoint);
                        template.setResourceSandboxURI(sandboxUrl);
                        Scope scope = APIUtil.findScopeByKey(scopeList, (String) mapEntryValue.get("scope"));
                        template.setScope(scope);
                        uriTemplates.add(template);
                    }
                }
                // todo handle casting exceptions
                api.setUriTemplates(uriTemplates);
                // todo clean out the code.
            } else {
                // following is the old fashioned way of processing resources
                NativeArray uriMethodArr = (NativeArray) apiData.get("uriMethodArr", apiData);
                NativeArray authTypeArr = (NativeArray) apiData.get("uriAuthMethodArr", apiData);
                NativeArray throttlingTierArr = (NativeArray) apiData.get("throttlingTierArr", apiData);
                if (uriTemplateArr != null && uriMethodArr != null && authTypeArr != null) {
                    if (uriTemplateArr.getLength() == uriMethodArr.getLength()) {
                        Set<URITemplate> uriTemplates = new LinkedHashSet<URITemplate>();
                        for (int i = 0; i < uriTemplateArr.getLength(); i++) {
                            String uriMethods = (String) uriMethodArr.get(i, uriMethodArr);
                            String uriMethodsAuthTypes = (String) authTypeArr.get(i, authTypeArr);
                            String[] uriMethodArray = uriMethods.split(",");
                            String[] authTypeArray = uriMethodsAuthTypes.split(",");
                            String uriMethodsThrottlingTiers = (String) throttlingTierArr.get(i, throttlingTierArr);
                            String[] throttlingTierArray = uriMethodsThrottlingTiers.split(",");
                            for (int k = 0; k < uriMethodArray.length; k++) {
                                for (int j = 0; j < authTypeArray.length; j++) {
                                    if (j == k) {
                                        URITemplate template = new URITemplate();
                                        String uriTemp = (String) uriTemplateArr.get(i, uriTemplateArr);
                                        String uriTempVal = uriTemp.startsWith("/") ? uriTemp : ("/" + uriTemp);
                                        template.setUriTemplate(uriTempVal);
                                        String throttlingTier = throttlingTierArray[j];

                                        if (isHTTPMethodValid(uriMethodArray[k])) {
                                            template.setHTTPVerb(uriMethodArray[k]);
                                        } else {
                                            handleException(
                                                    "Specified HTTP verb " + uriMethodArray[k] + " is invalid");
                                        }

                                        String authType = authTypeArray[j];
                                        if (authType.equals("Application & Application User")) {
                                            authType = APIConstants.AUTH_APPLICATION_OR_USER_LEVEL_TOKEN;
                                        }
                                        if (authType.equals("Application User")) {
                                            authType = "Application_User";
                                        }
                                        if (authType.equals("Application")) {
                                            authType = APIConstants.AUTH_APPLICATION_LEVEL_TOKEN;
                                        }

                                        template.setThrottlingTier(throttlingTier);
                                        template.setAuthType(authType);
                                        template.setResourceURI(endpoint);
                                        template.setResourceSandboxURI(sandboxUrl);

                                        uriTemplates.add(template);
                                        break;
                                    }

                                }
                            }

                        }
                        api.setUriTemplates(uriTemplates);
                    }
                }
            }
        }

        api.setDescription(StringEscapeUtils.escapeHtml(description));
        api.setWsdlUrl(wsdl);
        api.setWadlUrl(wadl);
        api.setLastUpdated(new Date());
        api.setUrl(endpoint);
        api.setSandboxUrl(sandboxUrl);
        api.addTags(tag);
        api.setTransports(transport);
        api.setApiOwner(apiOwner);
        api.setAdvertiseOnly(advertiseOnly);
        api.setRedirectURL(redirectURL);
        api.setSubscriptionAvailability(subscriptionAvailability);
        api.setSubscriptionAvailableTenants(subscriptionAvailableTenants);
        api.setResponseCache(responseCache);
        api.setCacheTimeout(cacheTimeOut);
        api.setAsDefaultVersion("default_version".equals(defaultVersion));

        api.setProductionMaxTps((String) apiData.get("productionTps", apiData));
        api.setSandboxMaxTps((String) apiData.get("sandboxTps", apiData));

        if (!"none".equals(inSequence)) {
            api.setInSequence(inSequence);
        }
        if (!"none".equals(outSequence)) {
            api.setOutSequence(outSequence);
        }

        List<String> sequenceList = apiProvider.getCustomFaultSequences(apiId);
        if (!"none".equals(faultSequence) && sequenceList.contains(faultSequence)) {
            api.setFaultSequence(faultSequence);
        }

        Set<Tier> availableTier = new HashSet<Tier>();
        String[] tierNames;
        if (tier != null) {
            tierNames = tier.split(",");
            if (!APIUtil.isAdvanceThrottlingEnabled()) {
                Set<Tier> definedTiers = apiProvider.getTiers();
                for (String tierName : tierNames) {
                    boolean isTierValid = false;
                    for (Tier definedTier : definedTiers) {
                        if (tierName.equals(definedTier.getName())) {
                            isTierValid = true;
                            break;
                        }
                    }

                    if (!isTierValid) {
                        handleException("Specified tier " + tierName + " does not exist");
                    }
                    availableTier.add(new Tier(tierName));
                }
            } else {
                Policy[] definedTiers = apiProvider.getPolicies(provider, PolicyConstants.POLICY_LEVEL_SUB);
                for (String tierName : tierNames) {
                    boolean isTierValid = false;
                    for (Policy definedTier : definedTiers) {
                        if (tierName.equals(definedTier.getPolicyName())) {
                            isTierValid = true;
                            break;
                        }
                    }

                    if (!isTierValid) {
                        handleException("Specified tier " + tierName + " does not exist");
                    }
                    availableTier.add(new Tier(tierName));
                }
            }

            api.addAvailableTiers(availableTier);
        }
        api.setStatus(APIStatus.CREATED);
        api.setContext(context);
        api.setContextTemplate(contextTemplate);
        api.setBusinessOwner(bizOwner);
        api.setBusinessOwnerEmail(bizOwnerEmail);
        api.setTechnicalOwner(techOwner);
        api.setTechnicalOwnerEmail(techOwnerEmail);
        api.setVisibility(visibility);
        api.setVisibleRoles(visibleRoles != null ? visibleRoles.trim() : null);
        api.setEnvironments(APIUtil.extractEnvironmentsForAPI(environments));
        CORSConfiguration corsConfiguration = APIUtil.getCorsConfigurationDtoFromJson(corsConfiguraion);
        if (corsConfiguration != null) {
            api.setCorsConfiguration(corsConfiguration);
        }
        String endpointConfig = (String) apiData.get("endpoint_config", apiData);
        if (StringUtils.isEmpty(endpointConfig)) {
            handleException("Endpoint Configuration is missing");
        } else {
            api.setEndpointConfig(endpointConfig);
            //Validate endpoint URI format
            validateEndpointURI(api.getEndpointConfig());
        }
        //set secured endpoint parameters
        if ("secured".equals(endpointSecured)) {
            api.setEndpointSecured(true);
            api.setEndpointUTUsername(endpointUTUsername);
            api.setEndpointUTPassword(endpointUTPassword);
            if ("digestAuth".equals(endpointAuthDigest)) {
                api.setEndpointAuthDigest(true);
            } else {
                api.setEndpointAuthDigest(false);
            }
        }

        checkFileSize(fileHostObject);
        boolean isTenantFlowStarted = false;
        try {
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(provider));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }

            apiProvider.addAPI(api);

            if (fileHostObject != null && fileHostObject.getJavaScriptFile().getLength() != 0) {

                String thumbPath = addThumbIcon(fileHostObject.getInputStream(),
                        fileHostObject.getJavaScriptFile().getContentType(), apiProvider, api);
                apiProvider.updateAPI(api);
            }
            NativeArray externalAPIStores = (NativeArray) apiData.get("externalAPIStores", apiData);
            int tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                    .getTenantId(tenantDomain);
            if (externalAPIStores.getLength() != 0) {
                Set<APIStore> apiStores = new HashSet<APIStore>();
                for (int k = 0; k < externalAPIStores.getLength(); k++) {
                    String apiStoreName = externalAPIStores.get(k, externalAPIStores).toString();
                    apiStores.add(APIUtil.getExternalAPIStore(apiStoreName, tenantId));
                }
                apiProvider.publishToExternalAPIStores(api, apiStores, false);
            }
            success = true;

        } catch (Exception e) {
            handleException("Error while adding the API- " + name + "-" + version, e);
            return false;
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        if (thumbUrl != null && !thumbUrl.isEmpty()) {
            try {
                URL url = new URL(thumbUrl);
                String imageType = url.openConnection().getContentType();
                File fileToUploadFromUrl = new File(ICON_PATH);
                if (!fileToUploadFromUrl.exists()) {
                    if (!fileToUploadFromUrl.createNewFile()) {
                        log.error("Unable to create new file under : " + ICON_PATH);
                    }
                }
                FileUtils.copyURLToFile(url, fileToUploadFromUrl);
                FileBody fileBody = new FileBody(fileToUploadFromUrl, imageType);

                checkImageSize(fileToUploadFromUrl);

                String thumbPath = addThumbIcon(fileBody.getInputStream(), url.openConnection().getContentType(),
                        apiProvider, api);

            } catch (IOException e) {
                handleException("[Error] Cannot read data from the URL", e);
            }
            apiProvider.updateAPI(api);

        }

        if (apiData.get("swagger", apiData) != null) {
            // Read URI Templates from swagger resource and set to api object
            Set<URITemplate> uriTemplates = definitionFromSwagger20.getURITemplates(api,
                    String.valueOf(apiData.get("swagger", apiData)));
            api.setUriTemplates(uriTemplates);

            // scopes
            Set<Scope> scopes = definitionFromSwagger20.getScopes(String.valueOf(apiData.get("swagger", apiData)));
            api.setScopes(scopes);

            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(provider));
            try {
                int tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                        .getTenantId(tenantDomain);
                for (URITemplate uriTemplate : uriTemplates) {
                    Scope scope = uriTemplate.getScope();
                    if (scope != null && !(APIUtil.isWhiteListedScope(scope.getKey()))) {
                        if (apiProvider.isScopeKeyAssigned(apiId, scope.getKey(), tenantId)) {
                            handleException("Scope " + scope.getKey() + " is already assigned by another API");
                        }
                    }
                }
            } catch (UserStoreException e) {
                handleException("Error while reading tenant information ", e);
            }

            // Save swagger in the registry
            apiProvider.saveSwagger20Definition(api.getId(), (String) apiData.get("swagger", apiData));
            saveAPI(apiProvider, api, null, false);
        } else {
            String apiDefinitionJSON = definitionFromSwagger20.generateAPIDefinition(api);
            apiProvider.saveSwagger20Definition(api.getId(), apiDefinitionJSON);
        }
        return success;

    }

    private static String addThumbIcon(InputStream inputStream, String contentType, APIProvider apiProvider,
            API api) throws APIManagementException {

        ResourceFile thumbIcon = new ResourceFile(inputStream, contentType);
        String thumbPath = APIUtil.getIconPath(api.getId());
        String thumbnailUrl = apiProvider.addResourceFile(thumbPath, thumbIcon);
        api.setThumbnailUrl(APIUtil.prependTenantPrefix(thumbnailUrl, api.getId().getProviderName()));

        /*Set permissions to anonymous role for thumbPath*/
        APIUtil.setResourcePermissions(api.getId().getProviderName(), null, null, thumbPath);
        return thumbPath;
    }

    private static boolean isHTTPMethodValid(String httpMethod) {
        boolean isValid = false;

        for (APIConstants.SupportedHTTPVerbs verb : APIConstants.SupportedHTTPVerbs.values()) {
            if (verb.name().equalsIgnoreCase(httpMethod)) {
                isValid = true;
            }
        }

        return isValid;
    }

    private static String checkAndSetVersionParam(String context) {
        // This is to support the new Pluggable version strategy
        // if the context does not contain any {version} segment, we use the default version strategy.
        if (!context.contains(VERSION_PARAM)) {
            if (!context.endsWith("/")) {
                context = context + "/";
            }
            context = context + VERSION_PARAM;
        }
        return context;
    }

    private static String getTransports(NativeObject apiData) {
        String transportStr = String.valueOf(apiData.get("transports", apiData));
        String transport = transportStr;
        if (transportStr != null) {
            if ((transportStr.indexOf(",") == 0) || (transportStr.indexOf(",") == (transportStr.length() - 1))) {
                transport = transportStr.replace(",", "");
            }
        }
        return transport;
    }

    public static boolean jsFunction_updateAPI(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException, FaultGatewaysException {

        if (args == null || args.length == 0) {
            handleException("Invalid number of input parameters.");
        }

        NativeObject apiData = (NativeObject) args[0];
        boolean success;
        String provider = String.valueOf(apiData.get("provider", apiData));
        if (provider != null) {
            provider = APIUtil.replaceEmailDomain(provider);
        }
        String name = (String) apiData.get("apiName", apiData);
        String version = (String) apiData.get("version", apiData);
        String defaultVersion = (String) apiData.get("defaultVersion", apiData);
        String description = (String) apiData.get("description", apiData);
        FileHostObject fileHostObject = (FileHostObject) apiData.get("imageUrl", apiData);
        String endpoint = (String) apiData.get("endpoint", apiData);
        String sandboxUrl = (String) apiData.get("sandbox", apiData);
        String techOwner = (String) apiData.get("techOwner", apiData);
        String techOwnerEmail = (String) apiData.get("techOwnerEmail", apiData);
        String bizOwner = (String) apiData.get("bizOwner", apiData);
        String bizOwnerEmail = (String) apiData.get("bizOwnerEmail", apiData);
        String visibility = (String) apiData.get("visibility", apiData);
        String thumbUrl = (String) apiData.get("thumbUrl", apiData);
        String environments = (String) apiData.get("environments", apiData);
        String corsConfiguraion = (String) apiData.get("corsConfiguration", apiData);
        String visibleRoles = "";
        if (visibility != null && visibility.equals(APIConstants.API_RESTRICTED_VISIBILITY)) {
            visibleRoles = (String) apiData.get("visibleRoles", apiData);
        }

        String visibleTenants = "";
        if (visibility != null && visibility.equals(APIConstants.API_CONTROLLED_VISIBILITY)) {
            visibleTenants = (String) apiData.get("visibleTenants", apiData);
        }
        String endpointSecured = (String) apiData.get("endpointSecured", apiData);
        String endpointAuthDigest = (String) apiData.get("endpointAuthDigest", apiData);
        String endpointUTUsername = (String) apiData.get("endpointUTUsername", apiData);
        String endpointUTPassword = (String) apiData.get("endpointUTPassword", apiData);

        String inSequence = (String) apiData.get("inSequence", apiData);
        String outSequence = (String) apiData.get("outSequence", apiData);
        String faultSequence = (String) apiData.get("faultSequence", apiData);

        String responseCache = (String) apiData.get("responseCache", apiData);
        int cacheTimeOut = APIConstants.API_RESPONSE_CACHE_TIMEOUT;
        if (APIConstants.ENABLED.equalsIgnoreCase(responseCache)) {
            responseCache = APIConstants.ENABLED;
            try {
                cacheTimeOut = Integer.parseInt((String) apiData.get("cacheTimeout", apiData));
            } catch (NumberFormatException e) {
                //ignore
            }
        } else {
            responseCache = APIConstants.DISABLED;
        }

        if (sandboxUrl != null && sandboxUrl.trim().length() == 0) {
            sandboxUrl = null;
        }

        if (endpoint != null && endpoint.trim().length() == 0) {
            endpoint = null;
        }

        if (endpoint != null && !endpoint.startsWith("http") && !endpoint.startsWith("https")) {
            endpoint = "http://" + endpoint;
        }
        if (sandboxUrl != null && !sandboxUrl.startsWith("http") && !sandboxUrl.startsWith("https")) {
            sandboxUrl = "http://" + sandboxUrl;
        }

        String redirectURL = (String) apiData.get("redirectURL", apiData);
        boolean advertiseOnly = Boolean.parseBoolean((String) apiData.get("advertiseOnly", apiData));
        String apiOwner = (String) apiData.get("apiOwner", apiData);

        if (apiOwner == null || apiOwner.equals("")) {
            apiOwner = provider;
        }

        String wsdl = (String) apiData.get("wsdl", apiData);
        String wadl = (String) apiData.get("wadl", apiData);
        String subscriptionAvailability = (String) apiData.get("subscriptionAvailability", apiData);
        String subscriptionAvailableTenants = "";
        if (subscriptionAvailability != null
                && subscriptionAvailability.equals(APIConstants.SUBSCRIPTION_TO_SPECIFIC_TENANTS)) {
            subscriptionAvailableTenants = (String) apiData.get("subscriptionTenants", apiData);
        }

        String tags = (String) apiData.get("tags", apiData);
        Set<String> tag = new HashSet<String>();
        if (tags != null) {
            if (tags.contains(",")) {
                String[] userTag = tags.split(",");
                tag.addAll(Arrays.asList(userTag).subList(0, tags.split(",").length));
            } else {
                tag.add(tags);
            }
        }
        provider = (provider != null ? provider.trim() : null);
        name = (name != null ? name.trim() : null);
        version = (version != null ? version.trim() : null);
        APIIdentifier oldApiId = new APIIdentifier(provider, name, version);
        APIProvider apiProvider = getAPIProvider(thisObj);
        boolean isTenantFlowStarted = false;
        String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(provider));
        if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
            isTenantFlowStarted = true;
            PrivilegedCarbonContext.startTenantFlow();
            PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
        }

        API oldApi = apiProvider.getAPI(oldApiId);

        String transport = getTransports(apiData);

        String tier = (String) apiData.get("tier", apiData);
        String apiLevelPolicy = (String) apiData.get("apiPolicy", apiData);
        String contextVal = (String) apiData.get("context", apiData);
        String context = contextVal.startsWith("/") ? contextVal : ("/" + contextVal);
        String providerDomain = MultitenantUtils.getTenantDomain(String.valueOf(apiData.get("provider", apiData)));
        if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equalsIgnoreCase(providerDomain)
                && !context.contains("/t/" + providerDomain)) {
            //Create tenant aware context for API
            context = "/t/" + providerDomain + context;
        }

        // This is to support the new Pluggable version strategy
        // if the context does not contain any {version} segment, we use the default version strategy.
        context = checkAndSetVersionParam(context);

        String contextTemplate = context;
        context = updateContextWithVersion(version, contextVal, context);

        APIIdentifier apiId = new APIIdentifier(provider, name, version);
        API api = new API(apiId);

        // to keep the backword compatibility if swagger not set process from
        // resource_config or old way.
        if (apiData.get("swagger", apiData) == null) {
            if (apiData.get("resource_config", apiData) != null) {
                Set<URITemplate> uriTemplates = new LinkedHashSet<URITemplate>();
                JSONParser parser = new JSONParser();
                JSONObject resourceConfig = null;
                try {
                    resourceConfig = (JSONObject) parser.parse((String) apiData.get("resource_config", apiData));
                } catch (ParseException e) {
                    handleException("Invalid resource config", e);
                } catch (ClassCastException e) {
                    handleException("Unable to create JSON object from resource config", e);
                }

                //process scopes
                JSONArray scopes = (JSONArray) resourceConfig.get("scopes");
                Set<Scope> scopeList = new LinkedHashSet<Scope>();
                for (int i = 0; i < scopes.size(); i++) {
                    Map scope = (Map) scopes.get(i); //access with get() method
                    Scope scopeObj = new Scope();
                    scopeObj.setKey((String) scope.get("key"));
                    scopeObj.setName((String) scope.get("name"));
                    scopeObj.setRoles((String) scope.get("roles"));
                    scopeObj.setDescription((String) scope.get("description"));
                    scopeList.add(scopeObj);
                }
                api.setScopes(scopeList);

                JSONArray resources = (JSONArray) resourceConfig.get("resources");
                for (int k = 0; k < resources.size(); k++) {
                    JSONObject resource = (JSONObject) resources.get(k);

                    Map http_verbs = (Map) resource.get("http_verbs");
                    Iterator iterator = http_verbs.entrySet().iterator();

                    while (iterator.hasNext()) {
                        Map.Entry mapEntry = (Map.Entry) iterator.next();
                        Map mapEntryValue = (Map) mapEntry.getValue();

                        URITemplate template = new URITemplate();
                        String uriTempVal = (String) resource.get("url_pattern");
                        uriTempVal = uriTempVal.startsWith("/") ? uriTempVal : ("/" + uriTempVal);
                        template.setUriTemplate(uriTempVal);
                        template.setHTTPVerb((String) mapEntry.getKey());
                        String authType = (String) mapEntryValue.get("auth_type");
                        if (authType.equals("Application & Application User")) {
                            authType = APIConstants.AUTH_APPLICATION_OR_USER_LEVEL_TOKEN;
                        }
                        if (authType.equals("Application User")) {
                            authType = "Application_User";
                        }
                        if (authType.equals("Application")) {
                            authType = APIConstants.AUTH_APPLICATION_LEVEL_TOKEN;
                        }
                        template.setThrottlingTier((String) mapEntryValue.get("throttling_tier"));
                        template.setAuthType(authType);
                        template.setResourceURI(endpoint);
                        template.setResourceSandboxURI(sandboxUrl);
                        Scope scope = APIUtil.findScopeByKey(scopeList, (String) mapEntryValue.get("scope"));
                        template.setScope(scope);
                        uriTemplates.add(template);
                    }
                }
                //todo handle casting exceptions
                api.setUriTemplates(uriTemplates);
                //todo clean out the code.
            } else {
                //following is the old fashioned way of processing resources
                NativeArray uriMethodArr = (NativeArray) apiData.get("uriMethodArr", apiData);
                NativeArray authTypeArr = (NativeArray) apiData.get("uriAuthMethodArr", apiData);
                NativeArray throttlingTierArr = (NativeArray) apiData.get("throttlingTierArr", apiData);
                NativeArray uriTemplateArr = (NativeArray) apiData.get("uriTemplateArr", apiData);
                if (uriTemplateArr != null && uriMethodArr != null && authTypeArr != null) {
                    if (uriTemplateArr.getLength() == uriMethodArr.getLength()) {
                        Set<URITemplate> uriTemplates = new LinkedHashSet<URITemplate>();
                        for (int i = 0; i < uriTemplateArr.getLength(); i++) {
                            String uriMethods = (String) uriMethodArr.get(i, uriMethodArr);
                            String uriMethodsAuthTypes = (String) authTypeArr.get(i, authTypeArr);
                            String[] uriMethodArray = uriMethods.split(",");
                            String[] authTypeArray = uriMethodsAuthTypes.split(",");
                            String uriMethodsThrottlingTiers = (String) throttlingTierArr.get(i, throttlingTierArr);
                            String[] throttlingTierArray = uriMethodsThrottlingTiers.split(",");
                            for (int k = 0; k < uriMethodArray.length; k++) {
                                for (int j = 0; j < authTypeArray.length; j++) {
                                    if (j == k) {
                                        URITemplate template = new URITemplate();
                                        String uriTemp = (String) uriTemplateArr.get(i, uriTemplateArr);
                                        String uriTempVal = uriTemp.startsWith("/") ? uriTemp : ("/" + uriTemp);
                                        template.setUriTemplate(uriTempVal);
                                        String throttlingTier = throttlingTierArray[j];
                                        template.setHTTPVerb(uriMethodArray[k]);
                                        String authType = authTypeArray[j];
                                        if (authType.equals("Application & Application User")) {
                                            authType = APIConstants.AUTH_APPLICATION_OR_USER_LEVEL_TOKEN;
                                        }
                                        if (authType.equals("Application User")) {
                                            authType = "Application_User";
                                        }
                                        if (authType.equals("Application")) {
                                            authType = APIConstants.AUTH_APPLICATION_LEVEL_TOKEN;
                                        }
                                        template.setThrottlingTier(throttlingTier);
                                        template.setAuthType(authType);
                                        template.setResourceURI(endpoint);
                                        template.setResourceSandboxURI(sandboxUrl);

                                        uriTemplates.add(template);
                                        break;
                                    }

                                }
                            }

                        }
                        api.setUriTemplates(uriTemplates);
                    }
                }
            }
        }

        api.setEnvironments(APIUtil.extractEnvironmentsForAPI(environments));
        CORSConfiguration corsConfiguration = APIUtil.getCorsConfigurationDtoFromJson(corsConfiguraion);
        if (corsConfiguration != null) {
            api.setCorsConfiguration(corsConfiguration);
        }
        api.setDescription(StringEscapeUtils.escapeHtml(description));
        api.setLastUpdated(new Date());
        api.setUrl(endpoint);
        api.setSandboxUrl(sandboxUrl);
        api.addTags(tag);
        api.setContext(context);
        api.setContextTemplate(contextTemplate);
        api.setVisibility(visibility);
        api.setVisibleRoles(visibleRoles != null ? visibleRoles.trim() : null);
        api.setVisibleTenants(visibleTenants != null ? visibleTenants.trim() : null);
        Set<Tier> availableTier = new HashSet<Tier>();
        if (tier != null) {
            String[] tierNames = tier.split(",");
            for (String tierName : tierNames) {
                availableTier.add(new Tier(tierName));
            }
            api.addAvailableTiers(availableTier);
        }

        if (apiLevelPolicy != null) {
            if ("none".equals(apiLevelPolicy)) {
                api.setApiLevelPolicy(null);
            } else {
                api.setApiLevelPolicy(apiLevelPolicy);
            }
        }

        api.setStatus(oldApi.getStatus());
        api.setWsdlUrl(wsdl);
        api.setWadlUrl(wadl);
        api.setLastUpdated(new Date());
        api.setBusinessOwner(bizOwner);
        api.setBusinessOwnerEmail(bizOwnerEmail);
        api.setTechnicalOwner(techOwner);
        api.setTechnicalOwnerEmail(techOwnerEmail);
        api.setTransports(transport);
        if (!"none".equals(inSequence)) {
            api.setInSequence(inSequence);
        }
        if (!"none".equals(outSequence)) {
            api.setOutSequence(outSequence);
        }

        List<String> sequenceList = apiProvider.getCustomFaultSequences(apiId);
        if (!"none".equals(faultSequence) && sequenceList.contains(faultSequence)) {
            api.setFaultSequence(faultSequence);
        }
        api.setOldInSequence(oldApi.getInSequence());
        api.setOldOutSequence(oldApi.getOutSequence());
        api.setOldFaultSequence(oldApi.getFaultSequence());
        api.setRedirectURL(redirectURL);
        api.setApiOwner(apiOwner);
        api.setAdvertiseOnly(advertiseOnly);

        // @todo needs to be validated
        api.setEndpointConfig((String) apiData.get("endpoint_config", apiData));
        //Validate endpoint URI format
        validateEndpointURI(api.getEndpointConfig());

        api.setProductionMaxTps((String) apiData.get("productionTps", apiData));
        api.setSandboxMaxTps((String) apiData.get("sandboxTps", apiData));

        api.setSubscriptionAvailability(subscriptionAvailability);
        api.setSubscriptionAvailableTenants(subscriptionAvailableTenants);
        api.setResponseCache(responseCache);
        api.setCacheTimeout(cacheTimeOut);
        api.setAsDefaultVersion("default_version".equals(defaultVersion));
        //set secured endpoint parameters
        if ("secured".equals(endpointSecured)) {
            api.setEndpointSecured(true);
            api.setEndpointUTUsername(endpointUTUsername);
            api.setEndpointUTPassword(endpointUTPassword);
            if ("digestAuth".equals(endpointAuthDigest)) {
                api.setEndpointAuthDigest(true);
            } else {
                api.setEndpointAuthDigest(false);
            }
        }

        try {
            checkFileSize(fileHostObject);

            if (fileHostObject != null && fileHostObject.getJavaScriptFile().getLength() != 0) {

                String thumbPath = addThumbIcon(fileHostObject.getInputStream(),
                        fileHostObject.getJavaScriptFile().getContentType(), apiProvider, api);

            } else if (oldApi.getThumbnailUrl() != null) {
                // retain the previously uploaded image
                api.setThumbnailUrl(oldApi.getThumbnailUrl());
            }

            if (thumbUrl != null && !thumbUrl.isEmpty()) {
                try {
                    URL url = new URL(thumbUrl);
                    String imageType = url.openConnection().getContentType();

                    File fileToUploadFromUrl = new File("tmp/icon");
                    if (!fileToUploadFromUrl.exists()) {
                        if (!fileToUploadFromUrl.createNewFile()) {
                            log.error("Unable to create new file under tmp/icon");
                        }
                    }
                    FileUtils.copyURLToFile(url, fileToUploadFromUrl);
                    FileBody fileBody = new FileBody(fileToUploadFromUrl, imageType);

                    checkImageSize(fileToUploadFromUrl);

                    String thumbPath = addThumbIcon(fileBody.getInputStream(),
                            url.openConnection().getContentType(), apiProvider, api);

                } catch (IOException e) {
                    handleException("[Error] Cannot read data from the URL", e);
                }
            }

            if (apiData.get("swagger", apiData) != null) {
                // Read URI Templates from swagger resource and set to api object
                Set<URITemplate> uriTemplates = definitionFromSwagger20.getURITemplates(api,
                        String.valueOf(apiData.get("swagger", apiData)));
                api.setUriTemplates(uriTemplates);

                // scopes
                Set<Scope> scopes = definitionFromSwagger20
                        .getScopes(String.valueOf(apiData.get("swagger", apiData)));
                api.setScopes(scopes);

                try {
                    int tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                            .getTenantId(tenantDomain);
                    for (URITemplate uriTemplate : uriTemplates) {
                        Scope scope = uriTemplate.getScope();
                        if (scope != null && !(APIUtil.isWhiteListedScope(scope.getKey()))) {
                            if (apiProvider.isScopeKeyAssigned(apiId, scope.getKey(), tenantId)) {
                                handleException("Scope " + scope.getKey() + " is already assigned by another API");
                            }
                        }
                    }
                } catch (UserStoreException e) {
                    handleException("Error while reading tenant information ", e);
                }

                // Save swagger in the registry
                apiProvider.saveSwagger20Definition(api.getId(), (String) apiData.get("swagger", apiData));
                saveAPI(apiProvider, api, null, false);
            } else {
                String apiDefinitionJSON = definitionFromSwagger20.generateAPIDefinition(api);
                apiProvider.saveSwagger20Definition(api.getId(), apiDefinitionJSON);
                apiProvider.updateAPI(api);
            }

            success = true;
        } catch (Exception e) {
            handleException("Error while updating the API- " + name + "-" + version, e);
            return false;
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }

        return success;
    }

    private static String updateContextWithVersion(String version, String contextVal, String context) {
        // This condition should not be true for any occasion but we keep it so that there are no loopholes in
        // the flow.
        if (version == null) {
            // context template patterns - /{version}/foo or /foo/{version}
            // if the version is null, then we remove the /{version} part from the context
            context = contextVal.replace("/" + VERSION_PARAM, "");
        } else {
            context = context.replace(VERSION_PARAM, version);
        }
        return context;
    }

    /**
     * This method used to change status of API
     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return true if the API was added successfully
     * @throws APIManagementException if API couldn't found
     * @throw FaultGatewaysException if any gateway couldn't update or create api
     */
    public static boolean jsFunction_updateAPIStatus(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException, FaultGatewaysException {
        if (args == null || args.length == 0) {
            handleException("Invalid number of input parameters.");
        }

        NativeObject apiData = (NativeObject) args[0];
        boolean success = false;
        String provider = (String) apiData.get("provider", apiData);
        String providerTenantMode = (String) apiData.get("provider", apiData);
        provider = APIUtil.replaceEmailDomain(provider);
        String name = (String) apiData.get("apiName", apiData);
        String version = (String) apiData.get("version", apiData);
        String status = (String) apiData.get("status", apiData);
        boolean publishToGateway = Boolean.parseBoolean((String) apiData.get("publishToGateway", apiData));
        boolean deprecateOldVersions = Boolean.parseBoolean((String) apiData.get("deprecateOldVersions", apiData));
        boolean makeKeysForwardCompatible = Boolean
                .parseBoolean((String) apiData.get("makeKeysForwardCompatible", apiData));
        boolean isTenantFlowStarted = false;
        try {
            String tenantDomain = MultitenantUtils
                    .getTenantDomain(APIUtil.replaceEmailDomainBack(providerTenantMode));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            APIProvider apiProvider = getAPIProvider(thisObj);
            APIIdentifier apiId = new APIIdentifier(provider, name, version);
            API api = apiProvider.getAPI(apiId);
            if (api != null) {
                APIStatus oldStatus = api.getStatus();
                APIStatus newStatus = getApiStatus(status);
                String currentUser = ((APIProviderHostObject) thisObj).getUsername();
                apiProvider.changeAPIStatus(api, newStatus, currentUser, publishToGateway);

                if ((oldStatus.equals(APIStatus.CREATED) || oldStatus.equals(APIStatus.PROTOTYPED))
                        && newStatus.equals(APIStatus.PUBLISHED)) {
                    if (makeKeysForwardCompatible) {
                        apiProvider.makeAPIKeysForwardCompatible(api);
                    }

                    if (deprecateOldVersions) {
                        List<API> apiList = apiProvider.getAPIsByProvider(provider);
                        APIVersionComparator versionComparator = new APIVersionComparator();
                        for (API oldAPI : apiList) {
                            if (oldAPI.getId().getApiName().equals(name)
                                    && versionComparator.compare(oldAPI, api) < 0
                                    && (oldAPI.getStatus().equals(APIStatus.PUBLISHED))) {
                                apiProvider.changeAPIStatus(oldAPI, APIStatus.DEPRECATED, currentUser,
                                        publishToGateway);
                            }
                        }
                    }
                }
                success = true;
            } else {
                handleException("Couldn't find an API with the name-" + name + "version-" + version);
            }
        } catch (FaultGatewaysException e) {
            handleFaultGateWayException(e);
            return false;
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return success;
    }

    public static boolean jsFunction_updateSubscriptionStatus(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        if (args == null || args.length == 0) {
            handleException("Invalid input parameters.");
        }

        NativeObject apiData = (NativeObject) args[0];
        boolean success = false;
        String provider = (String) apiData.get("provider", apiData);
        String name = (String) apiData.get("name", apiData);
        String version = (String) apiData.get("version", apiData);
        String newStatus = (String) args[1];
        int appId = Integer.parseInt((String) args[2]);

        try {
            APIProvider apiProvider = getAPIProvider(thisObj);
            APIIdentifier apiId = new APIIdentifier(provider, name, version);
            apiProvider.updateSubscription(apiId, newStatus, appId);
            return true;

        } catch (APIManagementException e) {
            handleException("Error while updating subscription status", e);
            return false;
        }

    }

    private static void checkFileSize(FileHostObject fileHostObject)
            throws ScriptException, APIManagementException {
        if (fileHostObject != null) {
            long length = fileHostObject.getJavaScriptFile().getLength();
            if (length / 1024.0 > APIConstants.MAX_FILE_SIZE) {
                handleException("Image file exceeds the maximum limit of 1MB");
            }
        }
    }

    private static void checkImageSize(File file) throws ScriptException, APIManagementException, IOException {

        if (file.exists()) {
            long length = file.length();
            if (length / 1024 > APIConstants.MAX_FILE_SIZE) {
                handleException("Image file exceeds the maximum limit of 1MB");
            }
        }
    }

    public static boolean jsFunction_updateTierPermissions(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        if (args == null || args.length == 0) {
            handleException("Invalid input parameters.");
        }

        NativeObject tierData = (NativeObject) args[0];
        boolean success = false;
        String tierName = (String) tierData.get("tierName", tierData);
        String permissionType = (String) tierData.get("permissiontype", tierData);
        String roles = (String) tierData.get("roles", tierData);

        try {
            APIProvider apiProvider = getAPIProvider(thisObj);
            apiProvider.updateTierPermissions(tierName, permissionType, roles);
            return true;

        } catch (APIManagementException e) {
            handleException("Error while updating subscription status", e);
            return false;
        }

    }

    public static boolean jsFunction_updateThrottleTierPermissions(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        if (args == null || args.length == 0) {
            handleException("Invalid input parameters.");
        }

        NativeObject tierData = (NativeObject) args[0];
        boolean success = false;
        String tierName = (String) tierData.get("policyName", tierData);
        String permissionType = (String) tierData.get("permissiontype", tierData);
        String roles = (String) tierData.get("roles", tierData);

        try {
            APIProvider apiProvider = getAPIProvider(thisObj);
            apiProvider.updateThrottleTierPermissions(tierName, permissionType, roles);
            return true;

        } catch (APIManagementException e) {
            handleException("Error while updating subscription status", e);
            return false;
        }

    }

    public static NativeArray jsFunction_getTierPermissions(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) {
        NativeArray myn = new NativeArray(0);
        APIProvider apiProvider = getAPIProvider(thisObj);
        /* Create an array with everyone role */
        String everyOneRoleName = ServiceReferenceHolder.getInstance().getRealmService()
                .getBootstrapRealmConfiguration().getEveryOneRoleName();
        String defaultRoleArray[] = new String[1];
        defaultRoleArray[0] = everyOneRoleName;
        try {
            Set<Tier> tiers = apiProvider.getTiers();
            Set<TierPermissionDTO> tierPermissions = apiProvider.getTierPermissions();
            int i = 0;
            if (tiers != null) {

                for (Tier tier : tiers) {
                    NativeObject row = new NativeObject();
                    boolean found = false;
                    for (TierPermissionDTO permission : tierPermissions) {
                        if (permission.getTierName().equals(tier.getName())) {
                            row.put("tierName", row, permission.getTierName());
                            row.put("tierDisplayName", row, tier.getDisplayName());
                            row.put("permissionType", row, permission.getPermissionType());
                            String[] roles = permission.getRoles();
                            /*If no roles defined return default role list*/
                            if (roles == null || roles.length == 0) {
                                row.put("roles", row, defaultRoleArray);
                            } else {
                                row.put("roles", row, permission.getRoles());
                            }
                            found = true;
                            break;
                        }
                    }
                    /* If no permissions has defined for this tier*/
                    if (!found) {
                        row.put("tierName", row, tier.getName());
                        row.put("tierDisplayName", row, tier.getDisplayName());
                        row.put("permissionType", row, APIConstants.TIER_PERMISSION_ALLOW);
                        row.put("roles", row, defaultRoleArray);
                    }
                    myn.put(i, myn, row);
                    i++;
                }
            }
        } catch (Exception e) {
            log.error("Error while getting available tiers", e);
        }
        return myn;
    }

    public static NativeArray jsFunction_getThrottleTierPermissions(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) {
        NativeArray myn = new NativeArray(0);
        APIProvider apiProvider = getAPIProvider(thisObj);
        /* Create an array with everyone role */
        String everyOneRoleName = ServiceReferenceHolder.getInstance().getRealmService()
                .getBootstrapRealmConfiguration().getEveryOneRoleName();
        String defaultRoleArray[] = new String[1];
        defaultRoleArray[0] = everyOneRoleName;
        try {
            Set<Tier> tiers = apiProvider.getTiers();
            Set<TierPermissionDTO> tierPermissions = apiProvider.getThrottleTierPermissions();
            int i = 0;
            if (tiers != null) {

                for (Tier tier : tiers) {
                    NativeObject row = new NativeObject();
                    boolean found = false;
                    for (TierPermissionDTO permission : tierPermissions) {
                        if (permission.getTierName().equals(tier.getName())) {
                            row.put("policyName", row, permission.getTierName());
                            row.put("tierDisplayName", row, tier.getDisplayName());
                            row.put("permissionType", row, permission.getPermissionType());
                            String[] roles = permission.getRoles();
                            /*If no roles defined return default role list*/
                            if (roles == null || roles.length == 0) {
                                row.put("roles", row, defaultRoleArray);
                            } else {
                                row.put("roles", row, permission.getRoles());
                            }
                            found = true;
                            break;
                        }
                    }
                    /* If no permissions has defined for this tier*/
                    if (!found) {
                        row.put("policyName", row, tier.getName());
                        row.put("tierDisplayName", row, tier.getDisplayName());
                        row.put("permissionType", row, APIConstants.TIER_PERMISSION_ALLOW);
                        row.put("roles", row, defaultRoleArray);
                    }
                    myn.put(i, myn, row);
                    i++;
                }
            }
        } catch (Exception e) {
            log.error("Error while getting available tiers", e);
        }
        return myn;
    }

    public static String jsFunction_getDefaultAPIVersion(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        String provider = args[0].toString();
        provider = APIUtil.replaceEmailDomain(provider);
        String apiname = args[1].toString();
        String version = ""; // unused attribute

        APIIdentifier apiid = new APIIdentifier(provider, apiname, version);
        APIProvider apiProvider1 = getAPIProvider(thisObj);
        return apiProvider1.getDefaultVersion(apiid);
    }

    public static boolean jsFunction_checkIfResourceExists(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        boolean result = false;

        if (args == null || args.length == 0) {
            handleException("Invalid number of parameters or their types.");
        }

        NativeObject apiData = (NativeObject) args[0];

        String providerName = String.valueOf(apiData.get("provider", apiData));
        //        String providerNameTenantFlow = args[0].toString();
        providerName = APIUtil.replaceEmailDomain(providerName);
        String apiName = (String) apiData.get("apiName", apiData);
        String version = (String) apiData.get("version", apiData);

        APIIdentifier apiId = new APIIdentifier(providerName, apiName, version);
        APIProvider apiProvider = getAPIProvider(thisObj);
        boolean isTenantFlowStarted = false;
        try {
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(providerName));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            result = apiProvider.checkIfAPIExists(apiId);
        } catch (Exception e) {
            handleException("Error occurred while checking if API exists " + apiName + "-" + version, e);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return result;
    }

    public static NativeArray jsFunction_getScopes(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {
        NativeArray myn = new NativeArray(0);

        if (args == null || !isStringValues(args)) {
            handleException("Invalid number of parameters or their types.");
        }
        String providerName = args[0].toString();
        //        String providerNameTenantFlow = args[0].toString();
        providerName = APIUtil.replaceEmailDomain(providerName);
        String scopeKey = args[1].toString();

        if (scopeKey != null && providerName != null) {
            Set<Scope> scopeSet = APIUtil.getScopeByScopeKey(scopeKey, providerName);
            JSONArray scopesNative = new JSONArray();
            for (Scope scope : scopeSet) {
                JSONObject scopeNative = new JSONObject();
                scopeNative.put("id", scope.getId());
                scopeNative.put("key", scope.getKey());
                scopeNative.put("name", scope.getName());
                scopeNative.put("roles", scope.getRoles());
                scopeNative.put("description", scope.getDescription());
                scopesNative.add(scopeNative);
            }
            myn.put(41, myn, scopesNative.toJSONString());
        } else {
            handleException("Scope Key or Provider Name not valid.");
        }
        return myn;
    }

    /**
     * This method is to functionality of getting an existing API to API-Provider based
     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return a native array
     * @throws APIManagementException Wrapped exception by org.wso2.carbon.apimgt.api.APIManagementException
     */

    public static NativeArray jsFunction_getAPI(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {
        NativeArray myn = new NativeArray(0);

        if (args == null || !isStringValues(args)) {
            handleException("Invalid number of parameters or their types.");
        }
        String providerName = args[0].toString();
        String providerNameTenantFlow = args[0].toString();
        providerName = APIUtil.replaceEmailDomain(providerName);
        String apiName = args[1].toString();
        String version = args[2].toString();

        APIIdentifier apiId = new APIIdentifier(providerName, apiName, version);
        APIProvider apiProvider = getAPIProvider(thisObj);
        boolean isTenantFlowStarted = false;
        try {
            String tenantDomain = MultitenantUtils
                    .getTenantDomain(APIUtil.replaceEmailDomainBack(providerNameTenantFlow));
            String userTenantDomain = MultitenantUtils.getTenantDomain(
                    APIUtil.replaceEmailDomainBack(((APIProviderHostObject) thisObj).getUsername()));
            if (!tenantDomain.equals(userTenantDomain)) {
                throw new APIManagementException(
                        "Invalid Operation: Cannot access API:" + apiId + "from current tenant.");
            }
            if (!MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }

            API api = null;
            try {
                api = apiProvider.getAPI(apiId);
            } catch (APIManagementException e) {
                handleException("Cannot find the requested API- " + apiName + "-" + version, e);
            }

            if (api != null) {
                Set<URITemplate> uriTemplates = api.getUriTemplates();

                myn.put(0, myn, checkValue(api.getId().getApiName()));
                myn.put(1, myn, checkValue(api.getDescription()));
                myn.put(2, myn, checkValue(api.getUrl()));
                myn.put(3, myn, checkValue(api.getWsdlUrl()));
                myn.put(4, myn, checkValue(api.getId().getVersion()));
                StringBuilder tagsSet = new StringBuilder("");
                for (int k = 0; k < api.getTags().toArray().length; k++) {
                    tagsSet.append(api.getTags().toArray()[k].toString());
                    if (k != api.getTags().toArray().length - 1) {
                        tagsSet.append(",");
                    }
                }
                myn.put(5, myn, checkValue(tagsSet.toString()));
                StringBuilder tiersSet = new StringBuilder("");
                StringBuilder tiersDisplayNamesSet = new StringBuilder("");
                StringBuilder tiersDescSet = new StringBuilder("");
                Set<Tier> tierSet = api.getAvailableTiers();
                Iterator it = tierSet.iterator();
                int j = 0;
                while (it.hasNext()) {
                    Object tierObject = it.next();
                    Tier tier = (Tier) tierObject;
                    tiersSet.append(tier.getName());
                    tiersDisplayNamesSet.append(tier.getDisplayName());
                    tiersDescSet.append(tier.getDescription());
                    if (j != tierSet.size() - 1) {
                        tiersSet.append(",");
                        tiersDisplayNamesSet.append(",");
                        tiersDescSet.append(",");
                    }
                    j++;
                }

                myn.put(6, myn, checkValue(tiersSet.toString()));
                myn.put(7, myn, checkValue(api.getStatus().toString()));
                myn.put(8, myn, getWebContextRoot(api.getThumbnailUrl()));
                myn.put(9, myn, api.getContext());
                myn.put(10, myn, checkValue(Long.valueOf(api.getLastUpdated().getTime()).toString()));
                myn.put(11, myn, getSubscriberCount(apiId, thisObj));

                if (uriTemplates.size() != 0) {
                    NativeArray uriTempArr = new NativeArray(uriTemplates.size());
                    Iterator i = uriTemplates.iterator();
                    List<NativeArray> uriTemplatesArr = new ArrayList<NativeArray>();
                    while (i.hasNext()) {
                        List<String> utArr = new ArrayList<String>();
                        URITemplate ut = (URITemplate) i.next();
                        utArr.add(ut.getUriTemplate());
                        utArr.add(ut.getMethodsAsString().replaceAll("\\s", ","));
                        utArr.add(ut.getAuthTypeAsString().replaceAll("\\s", ","));
                        utArr.add(ut.getThrottlingTiersAsString().replaceAll("\\s", ","));
                        NativeArray utNArr = new NativeArray(utArr.size());
                        for (int p = 0; p < utArr.size(); p++) {
                            utNArr.put(p, utNArr, utArr.get(p));
                        }
                        uriTemplatesArr.add(utNArr);
                    }

                    for (int c = 0; c < uriTemplatesArr.size(); c++) {
                        uriTempArr.put(c, uriTempArr, uriTemplatesArr.get(c));
                    }

                    myn.put(12, myn, uriTempArr);
                }

                myn.put(13, myn, checkValue(api.getSandboxUrl()));
                myn.put(14, myn, checkValue(tiersDescSet.toString()));
                myn.put(15, myn, checkValue(api.getBusinessOwner()));
                myn.put(16, myn, checkValue(api.getBusinessOwnerEmail()));
                myn.put(17, myn, checkValue(api.getTechnicalOwner()));
                myn.put(18, myn, checkValue(api.getTechnicalOwnerEmail()));
                myn.put(19, myn, checkValue(api.getWadlUrl()));
                myn.put(20, myn, checkValue(api.getVisibility()));
                myn.put(21, myn, checkValue(api.getVisibleRoles()));
                myn.put(22, myn, checkValue(api.getVisibleTenants()));
                myn.put(23, myn, checkValue(api.getEndpointUTUsername()));
                myn.put(24, myn, checkValue(api.getEndpointUTPassword()));
                myn.put(25, myn, checkValue(Boolean.toString(api.isEndpointSecured())));
                myn.put(26, myn, APIUtil.replaceEmailDomainBack(checkValue(api.getId().getProviderName())));
                myn.put(27, myn, checkTransport("http", api.getTransports()));
                myn.put(28, myn, checkTransport("https", api.getTransports()));
                Set<APIStore> storesSet = apiProvider.getExternalAPIStores(api.getId());
                if (storesSet != null && storesSet.size() != 0) {
                    NativeArray apiStoresArray = new NativeArray(0);
                    int i = 0;
                    for (APIStore store : storesSet) {
                        NativeObject storeObject = new NativeObject();
                        storeObject.put("name", storeObject, store.getName());
                        storeObject.put("displayName", storeObject, store.getDisplayName());
                        storeObject.put("published", storeObject, store.isPublished());
                        apiStoresArray.put(i, apiStoresArray, storeObject);
                        i++;
                    }
                    myn.put(29, myn, apiStoresArray);
                }
                myn.put(30, myn, checkValue(api.getInSequence()));
                myn.put(31, myn, checkValue(api.getOutSequence()));

                myn.put(32, myn, checkValue(api.getSubscriptionAvailability()));
                myn.put(33, myn, checkValue(api.getSubscriptionAvailableTenants()));

                //@todo need to handle backword compatibility
                myn.put(34, myn, checkValue(api.getEndpointConfig()));

                myn.put(35, myn, checkValue(api.getResponseCache()));
                myn.put(36, myn, checkValue(Integer.toString(api.getCacheTimeout())));
                myn.put(37, myn, checkValue(tiersDisplayNamesSet.toString()));

                myn.put(38, myn, checkValue(api.getFaultSequence()));

                //todo implement resource load

                if (uriTemplates.size() != 0) {
                    JSONArray resourceArray = new JSONArray();
                    Iterator i = uriTemplates.iterator();
                    List<NativeArray> uriTemplatesArr = new ArrayList<NativeArray>();
                    while (i.hasNext()) {
                        JSONObject resourceObj = new JSONObject();
                        URITemplate ut = (URITemplate) i.next();

                        resourceObj.put("url_pattern", ut.getUriTemplate());
                        resourceObj.put("http_verbs", JSONValue.parse(ut.getResourceMap()));

                        resourceArray.add(resourceObj);
                    }

                    myn.put(40, myn, JSONValue.toJSONString(resourceArray));
                }

                Set<Scope> scopes = api.getScopes();
                JSONArray scopesNative = new JSONArray();
                for (Scope scope : scopes) {
                    JSONObject scopeNative = new JSONObject();
                    scopeNative.put("id", scope.getId());
                    scopeNative.put("key", scope.getKey());
                    scopeNative.put("name", scope.getName());
                    scopeNative.put("roles", scope.getRoles());
                    scopeNative.put("description", scope.getDescription());
                    scopesNative.add(scopeNative);
                }
                myn.put(41, myn, scopesNative.toJSONString());
                myn.put(42, myn, checkValue(Boolean.toString(api.isDefaultVersion())));
                myn.put(43, myn, api.getImplementation());
                myn.put(44, myn, APIUtil.writeEnvironmentsToArtifact(api));
                //get new key manager
                KeyManager keyManager = KeyManagerHolder.getKeyManagerInstance();
                Map registeredResource = keyManager.getResourceByApiId(api.getId().toString());
                myn.put(45, myn, JSONObject.toJSONString(registeredResource));
                myn.put(46, myn, checkValue(api.getProductionMaxTps()));
                myn.put(47, myn, checkValue(api.getSandboxMaxTps()));
                myn.put(48, myn, checkValue(Boolean.toString(api.isEndpointAuthDigest())));
                CORSConfiguration corsConfigurationDto = api.getCorsConfiguration();
                if (corsConfigurationDto == null) {
                    corsConfigurationDto = new CORSConfiguration(false, Collections.EMPTY_LIST, false,
                            Collections.EMPTY_LIST, Collections.EMPTY_LIST);
                }
                String corsJson = APIUtil.getCorsConfigurationJsonFromDto(corsConfigurationDto);
                myn.put(49, myn, corsJson);

                StringBuilder policiesSet = new StringBuilder("");

                myn.put(50, myn, checkValue(policiesSet.toString()));
                myn.put(51, myn, checkValue(api.getApiLevelPolicy()));

            } else {
                handleException("Cannot find the requested API- " + apiName + "-" + version);
            }
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return myn;
    }

    public static NativeArray jsFunction_getSubscriberCountByAPIs(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        NativeArray myn = new NativeArray(0);
        String providerName = null;
        APIProvider apiProvider = getAPIProvider(thisObj);
        if (args == null || args.length == 0) {
            handleException("Invalid input parameters.");
        }
        boolean isTenantFlowStarted = false;
        try {
            providerName = APIUtil.replaceEmailDomain((String) args[0]);
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(providerName));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }

            if (providerName != null) {
                List<API> apiSet;
                if (providerName.equals("__all_providers__")) {
                    apiSet = apiProvider.getAllAPIs();
                } else {
                    apiSet = apiProvider.getAPIsByProvider(APIUtil.replaceEmailDomain(providerName));
                }

                Map<String, Long> subscriptions = new TreeMap<String, Long>();
                for (API api : apiSet) {
                    if (api.getStatus() == APIStatus.CREATED) {
                        continue;
                    }
                    long count = apiProvider.getAPISubscriptionCountByAPI(api.getId());
                    if (count == 0) {
                        continue;
                    }

                    String[] apiData = { api.getId().getApiName(), api.getId().getVersion(),
                            api.getId().getProviderName() };

                    JSONArray jsonArray = new JSONArray();
                    jsonArray.add(0, apiData[0]);
                    jsonArray.add(1, apiData[1]);
                    jsonArray.add(2, apiData[2]);
                    String key = jsonArray.toJSONString();

                    Long currentCount = subscriptions.get(key);
                    if (currentCount != null) {
                        subscriptions.put(key, currentCount + count);
                    } else {
                        subscriptions.put(key, count);
                    }
                }

                List<APISubscription> subscriptionData = new ArrayList<APISubscription>();
                for (Map.Entry<String, Long> entry : subscriptions.entrySet()) {
                    APISubscription sub = new APISubscription();
                    sub.name = entry.getKey();
                    sub.count = entry.getValue();
                    subscriptionData.add(sub);
                }

                int i = 0;
                for (APISubscription sub : subscriptionData) {
                    NativeObject row = new NativeObject();
                    row.put("apiName", row, sub.name);
                    row.put("count", row, sub.count);
                    myn.put(i, myn, row);
                    i++;
                }
            }
        } catch (Exception e) {
            handleException("Error while getting subscribers of the provider: " + providerName, e);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return myn;
    }

    public static NativeArray jsFunction_getTiers(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
        NativeArray myn = new NativeArray(1);
        APIProvider apiProvider = getAPIProvider(thisObj);
        try {
            Set<Tier> tiers = apiProvider.getTiers();
            List<Tier> tierList = APIUtil.sortTiers(tiers);
            int i = 0;
            if (tiers != null) {
                for (Tier tier : tierList) {
                    NativeObject row = new NativeObject();
                    row.put("tierName", row, tier.getName());
                    row.put("tierDisplayName", row, tier.getDisplayName());
                    row.put("tierDescription", row, tier.getDescription() != null ? tier.getDescription() : "");
                    row.put("defaultTier", row, i == 0);
                    myn.put(i, myn, row);
                    i++;
                }
            }
        } catch (Exception e) {
            log.error("Error while getting available tiers", e);
        }
        return myn;
    }

    public static NativeArray jsFunction_getSubscriberCountByAPIVersions(Context cx, Scriptable thisObj,
            Object[] args, Function funObj) throws APIManagementException {
        NativeArray myn = new NativeArray(0);
        String providerName = null;
        String apiName = null;
        APIProvider apiProvider = getAPIProvider(thisObj);
        if (args == null || args.length == 0) {
            handleException("Invalid input parameters.");
        }
        boolean isTenantFlowStarted = false;
        try {
            providerName = APIUtil.replaceEmailDomain((String) args[0]);
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(providerName));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            apiName = (String) args[1];
            if (providerName != null && apiName != null) {
                Map<String, Long> subscriptions = new TreeMap<String, Long>();
                Set<String> versions = apiProvider.getAPIVersions(APIUtil.replaceEmailDomain(providerName),
                        apiName);
                for (String version : versions) {
                    APIIdentifier id = new APIIdentifier(providerName, apiName, version);
                    API api = apiProvider.getAPI(id);
                    if (api.getStatus() == APIStatus.CREATED) {
                        continue;
                    }
                    long count = apiProvider.getAPISubscriptionCountByAPI(api.getId());

                    subscriptions.put(api.getId().getVersion(), count);
                }

                int i = 0;
                for (Map.Entry<String, Long> entry : subscriptions.entrySet()) {
                    NativeObject row = new NativeObject();
                    row.put("apiVersion", row, entry.getKey());
                    row.put("count", row, entry.getValue());
                    myn.put(i, myn, row);
                    i++;
                }
            }
        } catch (Exception e) {
            log.error("Error while getting subscribers of the " + "provider: " + providerName + " and API: "
                    + apiName, e);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return myn;
    }

    private static int getSubscriberCount(APIIdentifier apiId, Scriptable thisObj) throws APIManagementException {
        APIProvider apiProvider = getAPIProvider(thisObj);
        Set<Subscriber> subs = apiProvider.getSubscribersOfAPI(apiId);
        Set<String> subscriberNames = new HashSet<String>();
        if (subs != null) {
            for (Subscriber sub : subs) {
                subscriberNames.add(sub.getName());
            }
            return subscriberNames.size();
        } else {
            return 0;
        }
    }

    private static String checkTransport(String compare, String transport) throws APIManagementException {
        if (transport != null) {
            List<String> transportList = new ArrayList<String>();
            transportList.addAll(Arrays.asList(transport.split(",")));
            if (transportList.contains(compare)) {
                return "checked";
            } else {
                return "";
            }

        } else {
            return "";
        }
    }

    /**
     * This method is to functionality of getting all the APIs stored
     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return a native array
     * @throws APIManagementException Wrapped exception by org.wso2.carbon.apimgt.api.APIManagementException
     */
    public static NativeArray jsFunction_getAllAPIs(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {
        NativeArray myn = new NativeArray(0);
        APIProvider apiProvider = getAPIProvider(thisObj);

        try {
            List<API> apiList = apiProvider.getAllAPIs();
            if (apiList != null) {
                Iterator it = apiList.iterator();
                int i = 0;
                while (it.hasNext()) {
                    NativeObject row = new NativeObject();
                    Object apiObject = it.next();
                    API api = (API) apiObject;
                    APIIdentifier apiIdentifier = api.getId();
                    row.put("name", row, apiIdentifier.getApiName());
                    row.put("version", row, apiIdentifier.getVersion());
                    row.put("provider", row, APIUtil.replaceEmailDomainBack(apiIdentifier.getProviderName()));
                    row.put("status", row, checkValue(api.getStatus().toString()));
                    row.put("thumb", row, getWebContextRoot(api.getThumbnailUrl()));
                    row.put("subs", row, getSubscriberCount(apiIdentifier, thisObj));
                    myn.put(i, myn, row);
                    i++;

                }
            }
        } catch (Exception e) {
            handleException("Error occurred while getting the APIs", e);
        }
        return myn;
    }

    /**
     * This method is to functionality of getting all the APIs stored per provider
     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return a native array
     * @throws APIManagementException Wrapped exception by org.wso2.carbon.apimgt.api.APIManagementException
     */
    public static NativeArray jsFunction_getAPIsByProvider(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        NativeArray myn = new NativeArray(0);
        if (args == null || args.length == 0) {
            handleException("Invalid number of parameters.");
        }
        String providerName = (String) args[0];
        if (providerName != null) {
            APIProvider apiProvider = getAPIProvider(thisObj);
            boolean isTenantFlowStarted = false;
            try {
                String tenantDomain = MultitenantUtils
                        .getTenantDomain(APIUtil.replaceEmailDomainBack(providerName));
                if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                    isTenantFlowStarted = true;
                    PrivilegedCarbonContext.startTenantFlow();
                    PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
                }
                List<API> apiList = apiProvider.getAPIsByProvider(APIUtil.replaceEmailDomain(providerName));
                if (apiList != null) {
                    Iterator it = apiList.iterator();
                    int i = 0;
                    while (it.hasNext()) {
                        NativeObject row = new NativeObject();
                        Object apiObject = it.next();
                        API api = (API) apiObject;
                        APIIdentifier apiIdentifier = api.getId();
                        row.put("name", row, apiIdentifier.getApiName());
                        row.put("version", row, apiIdentifier.getVersion());
                        row.put("provider", row, APIUtil.replaceEmailDomainBack(apiIdentifier.getProviderName()));
                        row.put("lastUpdatedDate", row, api.getLastUpdated().toString());
                        myn.put(i, myn, row);
                        i++;
                    }
                }
            } catch (Exception e) {
                handleException("Error occurred while getting APIs for " + "the provider: " + providerName, e);
            } finally {
                if (isTenantFlowStarted) {
                    PrivilegedCarbonContext.endTenantFlow();
                }
            }
        }
        return myn;
    }

    public static NativeArray jsFunction_getSubscribedAPIs(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        String userName = null;
        NativeArray myn = new NativeArray(0);
        APIProvider apiProvider = getAPIProvider(thisObj);

        if (args == null || !isStringValues(args)) {
            handleException("Invalid number of parameters or their types.");
        }
        try {
            userName = (String) args[0];
            Subscriber subscriber = new Subscriber(userName);
            Set<API> apiSet = apiProvider.getSubscriberAPIs(subscriber);
            if (apiSet != null) {
                Iterator it = apiSet.iterator();
                int i = 0;
                while (it.hasNext()) {
                    NativeObject row = new NativeObject();
                    Object apiObject = it.next();
                    API api = (API) apiObject;
                    APIIdentifier apiIdentifier = api.getId();
                    row.put("apiName", row, apiIdentifier.getApiName());
                    row.put("version", row, apiIdentifier.getVersion());
                    row.put("provider", row, APIUtil.replaceEmailDomainBack(apiIdentifier.getProviderName()));
                    row.put("updatedDate", row, api.getLastUpdated().toString());
                    myn.put(i, myn, row);
                    i++;
                }
            }
        } catch (Exception e) {
            handleException("Error occurred while getting the subscribed APIs information " + "for the subscriber-"
                    + userName, e);
        }
        return myn;
    }

    public static NativeArray jsFunction_getAllAPIUsageByProvider(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {

        NativeArray myn = new NativeArray(0);
        String providerName = null;
        APIProvider apiProvider = getAPIProvider(thisObj);

        if (args == null || !isStringValues(args)) {
            handleException("Invalid input parameters.");
        }
        try {
            providerName = (String) args[0];
            if (providerName != null) {
                UserApplicationAPIUsage[] apiUsages = apiProvider.getAllAPIUsageByProvider(providerName);
                for (int i = 0; i < apiUsages.length; i++) {
                    NativeObject row = new NativeObject();
                    row.put("userName", row, apiUsages[i].getUserId());
                    row.put("application", row, apiUsages[i].getApplicationName());
                    row.put("appId", row, "" + apiUsages[i].getAppId());
                    row.put("token", row, apiUsages[i].getAccessToken());
                    row.put("tokenStatus", row, apiUsages[i].getAccessTokenStatus());
                    row.put("subStatus", row, apiUsages[i].getSubStatus());

                    StringBuilder apiSet = new StringBuilder("");
                    for (int k = 0; k < apiUsages[i].getApiSubscriptions().length; k++) {
                        apiSet.append(apiUsages[i].getApiSubscriptions()[k].getSubStatus());
                        apiSet.append("::");
                        apiSet.append(apiUsages[i].getApiSubscriptions()[k].getApiId().getApiName());
                        apiSet.append("::");
                        apiSet.append(apiUsages[i].getApiSubscriptions()[k].getApiId().getVersion());
                        apiSet.append("::");
                        apiSet.append(apiUsages[i].getApiSubscriptions()[k].getSubCreatedStatus());
                        if (k != apiUsages[i].getApiSubscriptions().length - 1) {
                            apiSet.append(",");
                        }
                    }
                    row.put("apis", row, apiSet.toString());
                    myn.put(i, myn, row);
                }
            }
        } catch (Exception e) {
            handleException("Error occurred while getting subscribers of the provider: " + providerName, e);
        }
        return myn;
    }

    public static NativeArray jsFunction_getAllDocumentation(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        String apiName = null;
        String version = null;
        String providerName;
        NativeArray myn = new NativeArray(0);
        APIProvider apiProvider = getAPIProvider(thisObj);
        if (args == null || !isStringValues(args)) {
            handleException("Invalid number of parameters or their types.");
        }
        boolean isTenantFlowStarted = false;
        try {
            providerName = (String) args[0];
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(providerName));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            apiName = (String) args[1];
            version = (String) args[2];
            APIIdentifier apiId = new APIIdentifier(APIUtil.replaceEmailDomain(providerName), apiName, version);

            List<Documentation> docsList = apiProvider.getAllDocumentation(apiId);
            Iterator it = docsList.iterator();
            int i = 0;
            while (it.hasNext()) {

                NativeObject row = new NativeObject();
                Object docsObject = it.next();
                Documentation doc = (Documentation) docsObject;
                Object objectSourceType = doc.getSourceType();
                String strSourceType = objectSourceType.toString();
                row.put("docName", row, doc.getName());
                row.put("docType", row, doc.getType().getType());
                row.put("sourceType", row, strSourceType);
                row.put("visibility", row, doc.getVisibility().name());
                row.put("docLastUpdated", row, (Long.valueOf(doc.getLastUpdated().getTime()).toString()));
                //row.put("sourceType", row, doc.getSourceType());
                if (Documentation.DocumentSourceType.URL.equals(doc.getSourceType())) {
                    row.put("sourceUrl", row, doc.getSourceUrl());
                }

                if (Documentation.DocumentSourceType.FILE.equals(doc.getSourceType())) {
                    row.put("filePath", row, doc.getFilePath());
                }

                if (doc.getType() == DocumentationType.OTHER) {
                    row.put("otherTypeName", row, doc.getOtherTypeName());
                }

                row.put("summary", row, doc.getSummary());
                myn.put(i, myn, row);
                i++;

            }

        } catch (Exception e) {
            handleException("Error occurred while getting documentation of the api - " + apiName + "-" + version,
                    e);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return myn;
    }

    public static NativeArray jsFunction_getInlineContent(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        String apiName;
        String version;
        String providerName;
        String docName;
        String content;
        NativeArray myn = new NativeArray(0);

        if (args == null || !isStringValues(args)) {
            handleException("Invalid number of parameters or their types.");
        }
        providerName = (String) args[0];
        apiName = (String) args[1];
        version = (String) args[2];
        docName = (String) args[3];
        APIIdentifier apiId = new APIIdentifier(APIUtil.replaceEmailDomain(providerName), apiName, version);
        APIProvider apiProvider = getAPIProvider(thisObj);

        try {
            content = apiProvider.getDocumentationContent(apiId, docName);
        } catch (Exception e) {
            handleException("Error while getting Inline Document Content ", e);
            return null;
        }

        NativeObject row = new NativeObject();
        row.put("providerName", row, APIUtil.replaceEmailDomainBack(providerName));
        row.put("apiName", row, apiName);
        row.put("apiVersion", row, version);
        row.put("docName", row, docName);
        row.put("content", row, content);
        myn.put(0, myn, row);
        return myn;
    }

    public static void jsFunction_addInlineContent(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {
        String apiName;
        String version;
        String providerName;
        String docName;
        String docContent;

        if (args == null || !isStringValues(args)) {
            handleException("Invalid number of parameters or their types.");
        }
        providerName = (String) args[0];
        apiName = (String) args[1];
        version = (String) args[2];
        docName = (String) args[3];
        docContent = (String) args[4];

        APIIdentifier apiId = new APIIdentifier(APIUtil.replaceEmailDomain(providerName), apiName, version);
        APIProvider apiProvider = getAPIProvider(thisObj);
        //        String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(providerName));
        try {
            API api = apiProvider.getAPI(apiId);
            apiProvider.addDocumentationContent(api, docName, docContent);
        } catch (APIManagementException e) {
            handleException("Error occurred while adding the content of the documentation- " + docName, e);
        }
    }

    public static boolean jsFunction_addDocumentation(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException, ScriptException {
        if (args == null || args.length == 0) {
            handleException("Invalid number of parameters or their types.");
        }
        boolean success = false;
        String providerName = (String) args[0];
        String apiName = (String) args[1];
        String version = (String) args[2];
        String docName = (String) args[3];
        String docType = (String) args[4];
        String summary = (String) args[5];
        String sourceType = (String) args[6];
        String otherTypeName = (String) args[9];

        //validate Source Type
        if (sourceType == null) {
            throw new APIManagementException("Invalid Source Type.");
        }
        sourceType = sourceType.trim();

        String visibility = (String) args[11];
        FileHostObject fileHostObject = null;
        String sourceURL;

        boolean isTenantFlowStarted = false;
        try {
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(providerName));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            APIIdentifier apiId = new APIIdentifier(APIUtil.replaceEmailDomain(providerName), apiName, version);
            Documentation doc = new Documentation(getDocType(docType), docName);
            APIProvider apiProvider = getAPIProvider(thisObj);

            //add documentation is allowed only if document name does not already exist for this api
            if (apiProvider.isDocumentationExist(apiId, docName)) {
                handleException("Error occurred while adding the document. " + docName + " already exists for API "
                        + apiName + '-' + version);
            }

            if (doc.getType() == DocumentationType.OTHER) {
                //validate otherTypeName
                if (otherTypeName == null || otherTypeName.trim().isEmpty()) {
                    throw new APIManagementException("Other Type Name Cannot be Empty.");
                }
                doc.setOtherTypeName(otherTypeName.trim());
            }

            if (Documentation.DocumentSourceType.URL.toString().equalsIgnoreCase(sourceType)) {
                doc.setSourceType(Documentation.DocumentSourceType.URL);
                sourceURL = args[7].toString();
                //validate urls
                if (sourceURL == null || !isURL(sourceURL.trim())) {
                    throw new APIManagementException("Invalid Document Url Format.");
                }
                sourceURL = sourceURL.trim();
                doc.setSourceUrl(sourceURL);
            } else if (Documentation.DocumentSourceType.FILE.toString().equalsIgnoreCase(sourceType)) {
                doc.setSourceType(Documentation.DocumentSourceType.FILE);
                fileHostObject = (FileHostObject) args[8];
            } else if (Documentation.DocumentSourceType.INLINE.toString().equalsIgnoreCase(sourceType)) {
                doc.setSourceType(Documentation.DocumentSourceType.INLINE);
            } else {
                throw new APIManagementException("Invalid Source Type.");
            }

            doc.setSummary(summary);

            if (visibility == null) {
                visibility = APIConstants.DOC_API_BASED_VISIBILITY;
            }
            if (Documentation.DocumentVisibility.API_LEVEL.toString().equalsIgnoreCase(visibility)) {
                doc.setVisibility(Documentation.DocumentVisibility.API_LEVEL);
            } else if (Documentation.DocumentVisibility.PRIVATE.toString().equalsIgnoreCase(visibility)) {
                doc.setVisibility(Documentation.DocumentVisibility.PRIVATE);
            } else {
                doc.setVisibility(Documentation.DocumentVisibility.OWNER_ONLY);
            }

            if (fileHostObject != null && fileHostObject.getJavaScriptFile().getLength() != 0) {
                String contentType = (String) args[10];
                apiProvider.addFileToDocumentation(apiId, doc, fileHostObject.getName(),
                        fileHostObject.getInputStream(), contentType);
            } else if (sourceType.equalsIgnoreCase(Documentation.DocumentSourceType.FILE.toString())) {
                throw new APIManagementException("Empty File Attachment.");
            }

            apiProvider.addDocumentation(apiId, doc);
            success = true;
        } catch (ScriptException e) {
            handleException("The attachment cannot be found for document- " + docName, e);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return success;
    }

    public static boolean jsFunction_removeDocumentation(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        if (args == null || !isStringValues(args)) {
            handleException("Invalid number of parameters or their types.");
        }
        boolean success;
        String providerName = (String) args[0];
        String apiName = (String) args[1];
        String version = (String) args[2];
        String docName = (String) args[3];
        String docType = (String) args[4];

        APIIdentifier apiId = new APIIdentifier(APIUtil.replaceEmailDomain(providerName), apiName, version);

        APIProvider apiProvider = getAPIProvider(thisObj);
        boolean isTenantFlowStarted = false;
        try {
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(providerName));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }

            apiProvider.removeDocumentation(apiId, docName, docType);
            success = true;
        } catch (APIManagementException e) {
            handleException("Error occurred while removing the document- " + docName + ".", e);
            return false;
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return success;
    }

    public static boolean jsFunction_createNewAPIVersion(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {

        boolean success;
        if (args == null || !isStringValues(args)) {
            handleException("Invalid number of parameters or their types.");
        }
        String providerName = (String) args[0];
        String apiName = (String) args[1];
        String version = (String) args[2];
        String newVersion = (String) args[3];
        String defaultVersion = (String) args[4];

        APIIdentifier apiId = new APIIdentifier(APIUtil.replaceEmailDomain(providerName), apiName, version);
        API api = new API(apiId);
        api.setAsDefaultVersion(defaultVersion.equals("default_version"));

        APIProvider apiProvider = getAPIProvider(thisObj);
        boolean isTenantFlowStarted = false;
        try {
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(providerName));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            apiProvider.createNewAPIVersion(api, newVersion);
            success = true;
        } catch (DuplicateAPIException e) {
            handleException("Error occurred while creating a new API version. " + e.getMessage());
            return false;
        } catch (Exception e) {
            handleException("Error occurred while creating a new API version: " + newVersion, e);
            return false;
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return success;
    }

    public static NativeArray jsFunction_getSubscribersOfAPI(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        String apiName;
        String version;
        String providerName;
        NativeArray myn = new NativeArray(0);
        if (args == null || !isStringValues(args)) {
            handleException("Invalid number of parameters or their types.");
        }

        providerName = (String) args[0];
        apiName = (String) args[1];
        version = (String) args[2];

        APIIdentifier apiId = new APIIdentifier(providerName, apiName, version);
        Set<Subscriber> subscribers;
        APIProvider apiProvider = getAPIProvider(thisObj);
        try {
            subscribers = apiProvider.getSubscribersOfAPI(apiId);
            Iterator it = subscribers.iterator();
            int i = 0;
            while (it.hasNext()) {
                NativeObject row = new NativeObject();
                Object subscriberObject = it.next();
                Subscriber user = (Subscriber) subscriberObject;
                row.put("userName", row, user.getName());
                row.put("subscribedDate", row,
                        checkValue(Long.valueOf(user.getSubscribedDate().getTime()).toString()));
                myn.put(i, myn, row);
                i++;
            }

        } catch (APIManagementException e) {
            handleException("Error occurred while getting subscribers of the API- " + apiName + "-" + version, e);
        }
        return myn;
    }

    public static String jsFunction_isContextExist(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {
        Boolean contextExist = false;
        if (args != null && isStringValues(args)) {
            String context = (String) args[0];
            String oldContext = (String) args[1];

            if (context.equals(oldContext)) {
                return contextExist.toString();
            }
            APIProvider apiProvider = getAPIProvider(thisObj);
            try {
                contextExist = apiProvider.isDuplicateContextTemplate(context);
            } catch (APIManagementException e) {
                handleException("Error while checking whether context exists", e);
            }
        } else {
            handleException("Input context value is null");
        }
        return contextExist.toString();
    }

    public static String jsFunction_isApiNameExist(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {
        Boolean apiExist = false;
        if (args != null && isStringValues(args)) {
            String apiName = (String) args[0];
            APIProvider apiProvider = getAPIProvider(thisObj);
            try {
                apiExist = apiProvider.isApiNameExist(apiName);
            } catch (APIManagementException e) {
                handleException("Error from registry while checking the api name is already exist", e);
            }
        } else {
            handleException("Input api name value is null");
        }
        return apiExist.toString();
    }

    private static DocumentationType getDocType(String docType) {
        DocumentationType docsType = null;
        for (DocumentationType type : DocumentationType.values()) {
            if (type.getType().equalsIgnoreCase(docType)) {
                docsType = type;
            }
        }
        return docsType;
    }

    private static boolean isStringValues(Object[] args) {
        int i = 0;
        for (Object arg : args) {

            if (!(arg instanceof String)) {
                return false;

            }
            i++;
        }
        return true;
    }

    private static String checkValue(String input) {
        return input != null ? input : "";
    }

    private static APIStatus getApiStatus(String status) {
        APIStatus apiStatus = null;
        for (APIStatus aStatus : APIStatus.values()) {
            if (aStatus.getStatus().equalsIgnoreCase(status)) {
                apiStatus = aStatus;
            }

        }
        return apiStatus;
    }

    public static NativeObject jsFunction_searchPaginatedAPIs(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        if (args == null || args.length < 4) {
            handleException("Invalid number of parameters.");
        }

        NativeArray myn = new NativeArray(0);
        NativeObject resultObj = new NativeObject();
        Map<String, Object> result = new HashMap<String, Object>();

        String providerName = (String) args[0];
        providerName = APIUtil.replaceEmailDomain(providerName);
        String inputSearchQuery = (String) args[1];
        int start = Integer.parseInt((String) args[2]);
        int end = Integer.parseInt((String) args[3]);
        boolean limitAttributes = false;
        String newSearchQuery = "";
        if (args.length == 5) {
            limitAttributes = Boolean.parseBoolean((String) args[4]);
        }

        /*String searchTerm;
        String searchType;
            
        if (searchValue.contains(":")) {
        if (searchValue.split(":").length > 1) {
            searchType = searchValue.split(":")[0];
            searchTerm = searchValue.split(":")[1];
        } else {
            throw new APIManagementException("Search term is missing. Try again with valid search query.");
        }
            
        } else {
        searchTerm = searchValue;
        searchType = "default";
        }*/
        inputSearchQuery = inputSearchQuery.trim();
        // sub context and doc content doesn't support AND search
        if (inputSearchQuery != null && inputSearchQuery.contains(" ")) {
            if (inputSearchQuery.split(" ").length > 1) {
                String[] searchCriterias = inputSearchQuery.split(" ");
                for (int i = 0; i < searchCriterias.length; i++) {
                    if (searchCriterias[i].contains(":") && searchCriterias[i].split(":").length > 1) {
                        if (APIConstants.DOCUMENTATION_SEARCH_TYPE_PREFIX
                                .equalsIgnoreCase(searchCriterias[i].split(":")[0])
                                || APIConstants.SUBCONTEXT_SEARCH_TYPE_PREFIX
                                        .equalsIgnoreCase(searchCriterias[i].split(":")[0])) {
                            throw new APIManagementException("Invalid query. AND based search is not supported for "
                                    + "doc and subcontext prefixes");
                        }
                    }
                    if (i == 0) {
                        newSearchQuery = APIUtil.getSingleSearchCriteria(searchCriterias[i]);
                    } else {
                        newSearchQuery = newSearchQuery + APIConstants.SEARCH_AND_TAG
                                + APIUtil.getSingleSearchCriteria(searchCriterias[i]);
                    }
                }
            }
        } else {
            newSearchQuery = APIUtil.getSingleSearchCriteria(inputSearchQuery);
        }
        try {
            /*if ("*".equals(searchTerm) || searchTerm.startsWith("*")) {
            searchTerm = searchTerm.replaceFirst("\\*", ".*");
            }*/
            APIProvider apiProvider = getAPIProvider(thisObj);
            String tenantDomain = MultitenantUtils.getTenantDomain(
                    APIUtil.replaceEmailDomainBack(((APIProviderHostObject) thisObj).getUsername()));
            result = apiProvider.searchPaginatedAPIs(newSearchQuery, tenantDomain, start, end, limitAttributes);

            if (newSearchQuery.startsWith(APIConstants.DOCUMENTATION_SEARCH_TYPE_PREFIX2)) {
                Map<Documentation, API> apiDocMap = (Map<Documentation, API>) result.get("apis");
                if (apiDocMap != null) {
                    int i = 0;
                    for (Map.Entry<Documentation, API> entry : apiDocMap.entrySet()) {
                        Documentation doc = entry.getKey();
                        API api = entry.getValue();
                        APIIdentifier apiIdentifier = api.getId();

                        NativeObject currentApi = new NativeObject();

                        currentApi.put("name", currentApi, apiIdentifier.getApiName());
                        currentApi.put("provider", currentApi,
                                APIUtil.replaceEmailDomainBack(apiIdentifier.getProviderName()));
                        currentApi.put("version", currentApi, apiIdentifier.getVersion());
                        currentApi.put("status", currentApi, checkValue(api.getStatus().toString()));
                        currentApi.put("thumb", currentApi, getWebContextRoot(api.getThumbnailUrl()));
                        currentApi.put("subs", currentApi, apiProvider.getSubscribersOfAPI(api.getId()).size());
                        if (providerName != null) {
                            currentApi.put("lastUpdatedDate", currentApi,
                                    checkValue(api.getLastUpdated().toString()));
                        }

                        currentApi.put("docName", currentApi, doc.getName());
                        currentApi.put("docSummary", currentApi, doc.getSummary());
                        currentApi.put("docSourceURL", currentApi, doc.getSourceUrl());
                        currentApi.put("docFilePath", currentApi, doc.getFilePath());

                        myn.put(i, myn, currentApi);
                        i++;
                    }
                    resultObj.put("apis", resultObj, myn);
                    resultObj.put("totalLength", resultObj, result.get("length"));
                }

            } else {
                Set<API> apiSet = (Set<API>) result.get("apis");
                //List<API> searchedList = apiProvider.searchAPIs(searchTerm, searchType, providerName);
                Iterator it = apiSet.iterator();
                int i = 0;
                while (it.hasNext()) {
                    NativeObject row = new NativeObject();
                    Object apiObject = it.next();
                    API api = (API) apiObject;
                    APIIdentifier apiIdentifier = api.getId();
                    row.put("name", row, apiIdentifier.getApiName());
                    row.put("provider", row, APIUtil.replaceEmailDomainBack(apiIdentifier.getProviderName()));
                    row.put("version", row, apiIdentifier.getVersion());
                    row.put("status", row, checkValue(api.getStatus().toString()));
                    row.put("thumb", row, getWebContextRoot(api.getThumbnailUrl()));
                    row.put("subs", row, apiProvider.getSubscribersOfAPI(api.getId()).size());
                    if (providerName != null) {
                        row.put("lastUpdatedDate", row, checkValue(api.getLastUpdated().toString()));
                    }
                    myn.put(i, myn, row);
                    i++;
                }
                resultObj.put("apis", resultObj, myn);
                resultObj.put("totalLength", resultObj, result.get("length"));
                resultObj.put("isMore", resultObj, result.get("isMore"));
            }
        } catch (Exception e) {
            handleException("Error occurred while getting the searched API- " + inputSearchQuery, e);
        }
        return resultObj;
    }

    public static NativeArray jsFunction_searchAPIs(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {
        NativeArray myn = new NativeArray(0);

        if (args == null || args.length == 0) {
            handleException("Invalid number of parameters.");
        }
        String providerName = (String) args[0];
        providerName = APIUtil.replaceEmailDomain(providerName);
        String searchValue = (String) args[1];
        String searchTerm;
        String searchType;

        if (searchValue.contains(":")) {
            if (searchValue.split(":").length > 1) {
                searchType = searchValue.split(":")[0];
                searchTerm = searchValue.split(":")[1];
            } else {
                throw new APIManagementException("Search term is missing. Try again with valid search query.");
            }

        } else {
            searchTerm = searchValue;
            searchType = "default";
        }
        try {
            if ("*".equals(searchTerm) || searchTerm.startsWith("*")) {
                searchTerm = searchTerm.replaceFirst("\\*", ".*");
            }
            APIProvider apiProvider = getAPIProvider(thisObj);

            if (APIConstants.DOCUMENTATION_SEARCH_TYPE_PREFIX.equalsIgnoreCase(searchType)) {
                Map<Documentation, API> apiDocMap = apiProvider.searchAPIsByDoc(searchTerm, searchType);
                if (apiDocMap != null) {
                    int i = 0;
                    for (Map.Entry<Documentation, API> entry : apiDocMap.entrySet()) {
                        Documentation doc = entry.getKey();
                        API api = entry.getValue();
                        APIIdentifier apiIdentifier = api.getId();

                        NativeObject currentApi = new NativeObject();

                        currentApi.put("name", currentApi, apiIdentifier.getApiName());
                        currentApi.put("provider", currentApi,
                                APIUtil.replaceEmailDomainBack(apiIdentifier.getProviderName()));
                        currentApi.put("version", currentApi, apiIdentifier.getVersion());
                        currentApi.put("status", currentApi, checkValue(api.getStatus().toString()));
                        currentApi.put("thumb", currentApi, getWebContextRoot(api.getThumbnailUrl()));
                        currentApi.put("subs", currentApi, apiProvider.getSubscribersOfAPI(api.getId()).size());
                        if (providerName != null) {
                            currentApi.put("lastUpdatedDate", currentApi,
                                    checkValue(api.getLastUpdated().toString()));
                        }

                        currentApi.put("docName", currentApi, doc.getName());
                        currentApi.put("docSummary", currentApi, doc.getSummary());
                        currentApi.put("docSourceURL", currentApi, doc.getSourceUrl());
                        currentApi.put("docFilePath", currentApi, doc.getFilePath());

                        myn.put(i, myn, currentApi);
                        i++;
                    }
                }

            } else {
                List<API> searchedList = apiProvider.searchAPIs(searchTerm, searchType, providerName);
                Iterator it = searchedList.iterator();
                int i = 0;
                while (it.hasNext()) {
                    NativeObject row = new NativeObject();
                    Object apiObject = it.next();
                    API api = (API) apiObject;
                    APIIdentifier apiIdentifier = api.getId();
                    row.put("name", row, apiIdentifier.getApiName());
                    row.put("provider", row, APIUtil.replaceEmailDomainBack(apiIdentifier.getProviderName()));
                    row.put("version", row, apiIdentifier.getVersion());
                    row.put("status", row, checkValue(api.getStatus().toString()));
                    row.put("thumb", row, getWebContextRoot(api.getThumbnailUrl()));
                    row.put("subs", row, apiProvider.getSubscribersOfAPI(api.getId()).size());
                    if (providerName != null) {
                        row.put("lastUpdatedDate", row, checkValue(api.getLastUpdated().toString()));
                    }
                    myn.put(i, myn, row);
                    i++;

                }
            }
        } catch (Exception e) {
            handleException("Error occurred while getting the searched API- " + searchValue, e);
        }
        return myn;
    }

    public static boolean jsFunction_hasCreatePermission(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) {
        APIProvider provider = getAPIProvider(thisObj);
        if (provider instanceof UserAwareAPIProvider) {
            try {
                ((UserAwareAPIProvider) provider).checkCreatePermission();
                return true;
            } catch (APIManagementException e) {
                return false;
            }
        }
        return false;
    }

    public static boolean jsFunction_hasManageTierPermission(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) {
        APIProvider provider = getAPIProvider(thisObj);
        if (provider instanceof UserAwareAPIProvider) {
            try {
                ((UserAwareAPIProvider) provider).checkManageTiersPermission();
                return true;
            } catch (APIManagementException e) {
                return false;
            }
        }
        return false;
    }

    public static boolean jsFunction_hasUserPermissions(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        if (args == null || !isStringValues(args)) {
            handleException("Invalid input parameters.");
        }
        String username = (String) args[0];
        return APIUtil.checkPermissionQuietly(username, APIConstants.Permissions.API_CREATE)
                || APIUtil.checkPermissionQuietly(username, APIConstants.Permissions.API_PUBLISH);
    }

    public static boolean jsFunction_hasPublishPermission(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) {
        APIProvider provider = getAPIProvider(thisObj);
        if (provider instanceof UserAwareAPIProvider) {
            try {
                ((UserAwareAPIProvider) provider).checkPublishPermission();
                return true;
            } catch (APIManagementException e) {
                return false;
            }
        }
        return false;
    }

    public static void jsFunction_loadRegistryOfTenant(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) {
        String tenantDomain = args[0].toString();
        if (tenantDomain != null
                && !org.wso2.carbon.base.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
            try {
                int tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                        .getTenantId(tenantDomain);
                APIUtil.loadTenantRegistry(tenantId);
            } catch (org.wso2.carbon.user.api.UserStoreException e) {
                log.error("Could not load tenant registry. Error while getting tenant id from tenant domain "
                        + tenantDomain, e);
            } catch (RegistryException e) {
                log.error("Could not load tenant registry for tenant " + tenantDomain, e);
            }
        }

    }

    /**
     * load axis configuration for the tenant
     *
     * @param cx
     * @param thisObj
     * @param args
     * @param funObj
     */
    public static void jsFunction_loadAxisConfigOfTenant(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) {
        String tenantDomain = args[0].toString();
        if (tenantDomain != null
                && !org.wso2.carbon.base.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
            APIUtil.loadTenantConfig(tenantDomain);
        }
    }

    public static NativeArray jsFunction_getLifeCycleEvents(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        NativeArray lifeCycles = new NativeArray(0);
        if (args == null) {
            handleException("Invalid input parameters.");
        }
        NativeObject apiData = (NativeObject) args[0];
        String provider = (String) apiData.get("provider", apiData);
        String name = (String) apiData.get("name", apiData);
        String version = (String) apiData.get("version", apiData);
        APIIdentifier apiId = new APIIdentifier(provider, name, version);
        APIProvider apiProvider = getAPIProvider(thisObj);
        try {
            List<LifeCycleEvent> lifeCycleEvents = apiProvider.getLifeCycleEvents(apiId);
            int i = 0;
            if (lifeCycleEvents != null) {
                for (LifeCycleEvent lcEvent : lifeCycleEvents) {
                    NativeObject event = new NativeObject();
                    event.put("username", event, APIUtil.replaceEmailDomainBack(checkValue(lcEvent.getUserId())));
                    event.put("newStatus", event,
                            lcEvent.getNewStatus() != null ? lcEvent.getNewStatus().toString() : "");
                    event.put("oldStatus", event,
                            lcEvent.getOldStatus() != null ? lcEvent.getOldStatus().toString() : "");

                    event.put("date", event, checkValue(Long.valueOf(lcEvent.getDate().getTime()).toString()));
                    lifeCycles.put(i, lifeCycles, event);
                    i++;
                }
            }
        } catch (APIManagementException e) {
            log.error("Error from registry while checking the input context is already exist", e);
        }
        return lifeCycles;
    }

    public static void jsFunction_removeAPI(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {
        if (args == null) {
            handleException("Invalid input parameters.");
        }
        NativeObject apiData = (NativeObject) args[0];

        String provider = (String) apiData.get("provider", apiData);
        provider = APIUtil.replaceEmailDomain(provider);
        String name = (String) apiData.get("name", apiData);
        String version = (String) apiData.get("version", apiData);
        APIIdentifier apiId = new APIIdentifier(provider, name, version);
        boolean isTenantFlowStarted = false;
        try {
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(provider));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }
            APIProvider apiProvider = getAPIProvider(thisObj);
            apiProvider.deleteAPI(apiId);
            KeyManager keyManager = KeyManagerHolder.getKeyManagerInstance();

            if (apiId.toString() != null) {
                keyManager.deleteRegisteredResourceByAPIId(apiId.toString());
            }

        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
    }

    private static class APISubscription {
        private String name;
        private long count;
        private String version;
    }

    public static boolean jsFunction_updateDocumentation(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException, ScriptException {
        if (args == null || args.length == 0) {
            handleException("Invalid number of parameters or their types.");
        }
        boolean success = false;
        String providerName = (String) args[0];
        providerName = APIUtil.replaceEmailDomain(providerName);
        String apiName = (String) args[1];
        String version = (String) args[2];
        String docName = (String) args[3];
        String docType = (String) args[4];
        String summary = (String) args[5];
        String sourceType = (String) args[6];
        String visibility = (String) args[10];
        String sourceURL = null;
        FileHostObject fileHostObject = null;

        boolean isTenantFlowStarted = false;
        try {
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(providerName));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }

            APIIdentifier apiId = new APIIdentifier(providerName, apiName, version);
            Documentation doc = new Documentation(getDocType(docType), docName);
            APIProvider apiProvider = getAPIProvider(thisObj);

            //update documentation is allowed only if documentation name already exists for this api
            if (!apiProvider.isDocumentationExist(apiId, docName)) {
                handleException("Error occurred while updating the document. " + docName
                        + " does not exist for API " + apiName + '-' + version);
            }

            if (doc.getType() == DocumentationType.OTHER) {
                doc.setOtherTypeName(args[9].toString());
            }

            if (Documentation.DocumentSourceType.URL.toString().equalsIgnoreCase(sourceType)) {
                doc.setSourceType(Documentation.DocumentSourceType.URL);
                sourceURL = args[7].toString();
            } else if (Documentation.DocumentSourceType.FILE.toString().equalsIgnoreCase(sourceType)) {
                doc.setSourceType(Documentation.DocumentSourceType.FILE);
                fileHostObject = (FileHostObject) args[8];
            } else {
                doc.setSourceType(Documentation.DocumentSourceType.INLINE);
            }
            doc.setSummary(summary);
            doc.setSourceUrl(sourceURL);
            if (visibility == null) {
                visibility = APIConstants.DOC_API_BASED_VISIBILITY;
            }
            if (Documentation.DocumentVisibility.API_LEVEL.toString().equalsIgnoreCase(visibility)) {
                doc.setVisibility(Documentation.DocumentVisibility.API_LEVEL);
            } else if (Documentation.DocumentVisibility.PRIVATE.toString().equalsIgnoreCase(visibility)) {
                doc.setVisibility(Documentation.DocumentVisibility.PRIVATE);
            } else {
                doc.setVisibility(Documentation.DocumentVisibility.OWNER_ONLY);
            }

            Documentation oldDoc = apiProvider.getDocumentation(apiId, doc.getType(), doc.getName());

            try {
                if (fileHostObject != null && fileHostObject.getJavaScriptFile().getLength() != 0) {
                    ResourceFile resourceFile = new ResourceFile(fileHostObject.getInputStream(),
                            fileHostObject.getJavaScriptFile().getContentType());
                    String filePath = APIUtil.getDocumentationFilePath(apiId, fileHostObject.getName());
                    doc.setFilePath(apiProvider.addResourceFile(filePath, resourceFile));
                } else if (oldDoc.getFilePath() != null) {
                    doc.setFilePath(oldDoc.getFilePath());
                }
            } catch (APIManagementException e) {
                handleException("Failed to add file to document " + doc.getName(), e);
            }
            apiProvider.updateDocumentation(apiId, doc);
            success = true;

        } catch (ScriptException e) {
            handleException("The attachment cannot be found for document- " + docName, e);
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return success;
    }

    public static boolean jsFunction_isAPIOlderVersionExist(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        boolean apiOlderVersionExist = false;
        if (args == null || args.length == 0) {
            handleException("Invalid number of input parameters.");
        }

        NativeObject apiData = (NativeObject) args[0];
        String provider = (String) apiData.get("provider", apiData);
        provider = APIUtil.replaceEmailDomain(provider);
        String name = (String) apiData.get("name", apiData);
        String currentVersion = (String) apiData.get("version", apiData);
        boolean isTenantFlowStarted = false;
        try {
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(provider));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }

            APIProvider apiProvider = getAPIProvider(thisObj);
            Set<String> versions = apiProvider.getAPIVersions(provider, name);
            APIVersionStringComparator comparator = new APIVersionStringComparator();
            for (String version : versions) {
                if (comparator.compare(version, currentVersion) < 0) {
                    apiOlderVersionExist = true;
                    break;
                }
            }
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        return apiOlderVersionExist;
    }

    /**
     * This method is used to edit the endpoint URL provided during the implementation stage in the publisher
     * based on the resource url patterns provided in the design stage of an API.It is used in jsFunction_isURLValid()
     */
    public static NativeObject editEndpointUrlToTest(String urlVal, Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {

        String urlValue = urlVal;
        boolean isContainUriTemplatesOnly = false;
        NativeObject data = new NativeObject();

        if (args == null || !isStringValues(args)) {
            handleException("Invalid number of parameters or their types.");
        }

        String providerName = args.length > 2 ? (String) args[2] : "";
        String apiName = args.length > 3 ? (String) args[3] : "";
        String apiVersion = args.length > 4 ? (String) args[4] : "";

        if (providerName != null) {
            providerName = APIUtil.replaceEmailDomain(providerName);
        }

        APIIdentifier apiIdentifier = new APIIdentifier(providerName, apiName, apiVersion);
        APIProvider apiProvider = getAPIProvider(thisObj);

        API api = null;
        try {
            api = apiProvider.getAPI(apiIdentifier);
        } catch (APIManagementException e) {
            handleException("Cannot find the requested API- " + apiName + "-" + apiVersion, e);
        }

        if (api != null) {

            Set<URITemplate> uriTemplates = api.getUriTemplates();

            if (uriTemplates.size() != 0) {

                Iterator i = uriTemplates.iterator();
                List<String> urlPatternArray = new ArrayList<String>();
                while (i.hasNext()) {
                    URITemplate ut = (URITemplate) i.next();
                    urlPatternArray.add(ut.getUriTemplate());
                }

                if (urlPatternArray.contains("/*")) { //Checking whether the urlPatternArray contains /*
                    data.put("urlValue", data, urlValue);
                    data.put("isContainUriTemplatesOnly", data, false);
                    return data;
                } else {
                    for (String urlPattern : urlPatternArray) {
                        //to check whether it is a uri-template
                        Matcher matcher = pathParamExtractorPattern.matcher(urlPattern);

                        if (matcher.find()) {
                            isContainUriTemplatesOnly = true;
                        } else {
                            urlValue = urlValue + urlPattern;
                            isContainUriTemplatesOnly = false;
                            break;
                        }
                    }
                }

            }
        }

        data.put("urlValue", data, urlValue);
        data.put("isContainUriTemplatesOnly", data, isContainUriTemplatesOnly);
        return data;

    }

    public static NativeObject jsFunction_isURLValid(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {
        boolean isConnectionError = true;
        String response = null;
        boolean isContainUriTemplatesOnly = false;//To check whether the resources contain only uri templates
        NativeObject data = new NativeObject();

        if (args == null || !isStringValues(args)) {
            handleException("Invalid input parameters.");
        }
        String urlVal = (String) args[1];
        String type = (String) args[0];
        String providerName = args.length > 2 ? (String) args[2] : "";
        String apiName = args.length > 3 ? (String) args[3] : "";
        String apiVersion = args.length > 4 ? (String) args[4] : "";
        String invalidStatusCodesRegex = args.length > 5 ? (String) args[5] : "404";
        if (urlVal != null && !urlVal.isEmpty()) {
            urlVal = urlVal.trim();

            try {

                if (type != null && type.equals("wsdl")) {
                    validateWsdl(urlVal);
                    response = "success";
                    isConnectionError = false;
                } else {
                    // checking http,https endpoints up to resource level by doing
                    // http HEAD. And other end point
                    // validation do through basic url connect
                    if (!StringUtils.equals(providerName, "") && !StringUtils.equals(apiName, "")
                            && !StringUtils.equals(apiVersion, "")) { //To escape editing the url for auto validation of wsdl endpoints

                        NativeObject obj = editEndpointUrlToTest(urlVal, cx, thisObj, args, funObj);
                        urlVal = (String) obj.get("urlValue");

                        if (obj.get("isContainUriTemplatesOnly").equals(true)) {
                            isContainUriTemplatesOnly = true;
                        }
                    }

                    URL url = new URL(urlVal);

                    if (url.getProtocol().matches("https")) {
                        ServerConfiguration serverConfig = CarbonUtils.getServerConfiguration();
                        String trustStorePath = serverConfig.getFirstProperty("Security.TrustStore.Location");
                        String trustStorePassword = serverConfig.getFirstProperty("Security.TrustStore.Password");
                        System.setProperty("javax.net.ssl.trustStore", trustStorePath);
                        System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);

                        NativeObject headRequestResult = sendHttpHEADRequest(urlVal, invalidStatusCodesRegex);
                        headRequestResult.put("isContainUriTemplatesOnly", headRequestResult,
                                isContainUriTemplatesOnly);
                        return headRequestResult;

                    } else if (url.getProtocol().matches("http")) {
                        NativeObject headRequestResult = sendHttpHEADRequest(urlVal, invalidStatusCodesRegex);
                        headRequestResult.put("isContainUriTemplatesOnly", headRequestResult,
                                isContainUriTemplatesOnly);
                        return headRequestResult;
                    }
                }
            } catch (Exception e) {
                response = e.getMessage();
            }
        }

        data.put("response", data, response);
        data.put("isConnectionError", data, isConnectionError);
        data.put("isContainUriTemplatesOnly", data, isContainUriTemplatesOnly);
        return data;

    }

    private static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    private boolean resourceMethodMatches(String[] resourceMethod1, String[] resourceMethod2) {
        for (String m1 : resourceMethod1) {
            for (String m2 : resourceMethod2) {
                if (m1.equals(m2)) {
                    return true;
                }
            }
        }
        return false;
    }

    private static void validateWsdl(String url) throws Exception {

        //If url is empty or null throw exception
        if (StringUtils.isEmpty(url)) {
            handleException("URL is not empty");
        }

        if (url.startsWith(APIConstants.WSDL_REGISTRY_LOCATION_PREFIX)) {
            url = APIUtil.getServerURL() + url;
        }

        URL wsdl = new URL(url);
        BufferedReader in = new BufferedReader(new InputStreamReader(wsdl.openStream(), Charset.defaultCharset()));
        String inputLine;
        boolean isWsdl2 = false;
        boolean isWsdl10 = false;
        StringBuilder urlContent = new StringBuilder();
        try {
            while ((inputLine = in.readLine()) != null) {
                String wsdl2NameSpace = "http://www.w3.org/ns/wsdl";
                String wsdl10NameSpace = "http://schemas.xmlsoap.org/wsdl/";
                urlContent.append(inputLine);
                isWsdl2 = urlContent.indexOf(wsdl2NameSpace) > 0;
                isWsdl10 = urlContent.indexOf(wsdl10NameSpace) > 0;
            }
        } finally {
            in.close();
        }

        if (isWsdl10) {
            javax.wsdl.xml.WSDLReader wsdlReader11 = javax.wsdl.factory.WSDLFactory.newInstance().newWSDLReader();
            wsdlReader11.readWSDL(url);
        } else if (isWsdl2) {
            WSDLReader wsdlReader20 = WSDLFactory.newInstance().newWSDLReader();
            wsdlReader20.readWSDL(url);
        } else {
            handleException("URL is not in format of wsdl1/wsdl2");
        }

    }

    private static String getWebContextRoot(String postfixUrl) {
        String webContext = CarbonUtils.getServerConfiguration().getFirstProperty("WebContextRoot");
        if (postfixUrl != null && webContext != null && !webContext.equals("/")) {
            postfixUrl = webContext + postfixUrl;
        }
        return postfixUrl;
    }

    public static NativeArray jsFunction_searchAccessTokens(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws Exception {
        NativeObject tokenInfo;
        NativeArray tokenInfoArr = new NativeArray(0);
        if (args == null || !isStringValues(args)) {
            handleException("Invalid input parameters.");
        }
        String searchValue = (String) args[0];
        String searchTerm;
        String searchType;
        APIProvider apiProvider = getAPIProvider(thisObj);
        Map<Integer, APIKey> tokenData;
        String loggedInUser = ((APIProviderHostObject) thisObj).getUsername();

        if (searchValue.contains(":")) {
            searchTerm = searchValue.split(":")[1];
            searchType = searchValue.split(":")[0];
            if ("*".equals(searchTerm) || searchTerm.startsWith("*")) {
                searchTerm = searchTerm.replaceFirst("\\*", ".*");
            }
            tokenData = apiProvider.searchAccessToken(searchType, searchTerm, loggedInUser);
        } else {
            //Check whether old access token is already available
            if (apiProvider.isApplicationTokenExists(searchValue)) {
                APIKey tokenDetails = apiProvider.getAccessTokenData(searchValue);
                if (tokenDetails.getAccessToken() == null) {
                    throw new APIManagementException(
                            "The requested access token is already revoked or No access token available as per requested.");
                }
                tokenData = new HashMap<Integer, APIKey>();
                tokenData.put(0, tokenDetails);
            } else {
                if ("*".equals(searchValue) || searchValue.startsWith("*")) {
                    searchValue = searchValue.replaceFirst("\\*", ".*");
                }
                tokenData = apiProvider.searchAccessToken(null, searchValue, loggedInUser);
            }
        }
        if (tokenData != null && tokenData.size() != 0) {
            for (int i = 0; i < tokenData.size(); i++) {
                tokenInfo = new NativeObject();
                tokenInfo.put("token", tokenInfo, tokenData.get(i).getAccessToken());
                tokenInfo.put("user", tokenInfo, tokenData.get(i).getAuthUser());
                tokenInfo.put("scope", tokenInfo, tokenData.get(i).getTokenScope());
                tokenInfo.put("createTime", tokenInfo, tokenData.get(i).getCreatedDate());
                if (tokenData.get(i).getValidityPeriod() == Long.MAX_VALUE) {
                    tokenInfo.put("validTime", tokenInfo, "Won't Expire");
                } else {
                    tokenInfo.put("validTime", tokenInfo, tokenData.get(i).getValidityPeriod());
                }
                tokenInfo.put("consumerKey", tokenInfo, tokenData.get(i).getConsumerKey());
                tokenInfoArr.put(i, tokenInfoArr, tokenInfo);
            }
        } else {
            throw new APIManagementException(
                    "The requested access token is already revoked or No access token available as per requested.");
        }

        return tokenInfoArr;

    }

    public static void jsFunction_revokeAccessToken(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws Exception {
        if (args == null || !isStringValues(args)) {
            handleException("Invalid input parameters.");
        }
        String accessToken = (String) args[0];
        String consumerKey = (String) args[1];
        String authUser = (String) args[2];
        APIProvider apiProvider = getAPIProvider(thisObj);

        try {
            SubscriberKeyMgtClient keyMgtClient = HostObjectUtils.getKeyManagementClient();
            if (keyMgtClient != null) {
                keyMgtClient.revokeAccessToken(accessToken, consumerKey, authUser);
            }

            Set<APIIdentifier> apiIdentifierSet = apiProvider.getAPIByAccessToken(accessToken);
            List<org.wso2.carbon.apimgt.handlers.security.stub.types.APIKeyMapping> mappings = new ArrayList<org.wso2.carbon.apimgt.handlers.security.stub.types.APIKeyMapping>();
            for (APIIdentifier apiIdentifier : apiIdentifierSet) {
                org.wso2.carbon.apimgt.handlers.security.stub.types.APIKeyMapping mapping = new org.wso2.carbon.apimgt.handlers.security.stub.types.APIKeyMapping();
                API apiDefinition = apiProvider.getAPI(apiIdentifier);
                mapping.setApiVersion(apiIdentifier.getVersion());
                mapping.setContext(apiDefinition.getContext());
                mapping.setKey(accessToken);
                mappings.add(mapping);
            }
            if (mappings.size() > 0) {
                APIManagerConfiguration config = ServiceReferenceHolder.getInstance()
                        .getAPIManagerConfigurationService().getAPIManagerConfiguration();
                Map<String, Environment> gatewayEnvs = config.getApiGatewayEnvironments();
                for (Environment environment : gatewayEnvs.values()) {
                    APIAuthenticationAdminClient client = new APIAuthenticationAdminClient(environment);
                    client.invalidateKeys(mappings);
                }

            }
        } catch (Exception e) {
            handleException("Error while revoking the access token: " + accessToken, e);

        }

    }

    public static boolean jsFunction_validateRoles(Context cx, Scriptable thisObj, Object[] args, Function funObj) {
        if (args == null || args.length == 0) {
            return false;
        }

        boolean valid = false;
        String inputRolesSet = (String) args[0];
        String username = (String) args[1];
        String[] inputRoles = null;
        if (inputRolesSet != null) {
            inputRoles = inputRolesSet.split(",");
        }

        try {
            String[] roles = APIUtil.getRoleNames(username);

            if (roles != null && inputRoles != null) {
                for (String inputRole : inputRoles) {
                    for (String role : roles) {
                        valid = (inputRole.equals(role));
                        if (valid) { //If we found a match for the input role,then no need to process the for loop further
                            break;
                        }
                    }
                    //If the input role doesn't match with any of the role existing in the system
                    if (!valid) {
                        return valid;
                    }

                }
                return valid;
            }
        } catch (Exception e) {
            log.error("Error while validating the input roles.", e);
        }

        return valid;
    }

    /**
     * Retrieves custom sequences from registry
     * @param cx
     * @param thisObj
     * @param args
     * @param funObj
     * @return
     * @throws APIManagementException
     */
    public static NativeArray jsFunction_getCustomOutSequences(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        if (args == null || args.length < 3) {
            handleException("Invalid input parameters.");
        }
        APIProvider apiProvider = getAPIProvider(thisObj);
        String apiName = (String) args[0];
        String apiVersion = (String) args[1];
        String provider = (String) args[2];

        if (provider != null) {
            provider = APIUtil.replaceEmailDomain(provider);
        }
        APIIdentifier apiIdentifier = new APIIdentifier(provider, apiName, apiVersion);

        List<String> sequenceList = apiProvider.getCustomOutSequences(apiIdentifier);

        NativeArray myn = new NativeArray(0);
        if (sequenceList == null) {
            return null;
        } else {
            for (int i = 0; i < sequenceList.size(); i++) {
                myn.put(i, myn, sequenceList.get(i));
            }
            return myn;
        }

    }

    /**
      * Retrieves custom sequences from registry
      * @param cx
      * @param thisObj
      * @param args
      * @param funObj
      * @return
      * @throws APIManagementException
      */
    public static NativeArray jsFunction_getCustomInSequences(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        if (args == null || args.length < 3) {
            handleException("Invalid input parameters.");
        }
        APIProvider apiProvider = getAPIProvider(thisObj);

        String apiName = (String) args[0];
        String apiVersion = (String) args[1];
        String provider = (String) args[2];

        if (provider != null) {
            provider = APIUtil.replaceEmailDomain(provider);
        }
        APIIdentifier apiIdentifier = new APIIdentifier(provider, apiName, apiVersion);

        List<String> sequenceList = apiProvider.getCustomInSequences(apiIdentifier);

        NativeArray myn = new NativeArray(0);
        if (sequenceList == null) {
            return null;
        } else {
            for (int i = 0; i < sequenceList.size(); i++) {
                myn.put(i, myn, sequenceList.get(i));
            }
            return myn;
        }

    }

    /**
     * Retrieves custom fault sequences from registry
     * @param cx
     * @param thisObj
     * @param args
     * @param funObj
     * @return
     * @throws APIManagementException
     */
    public static NativeArray jsFunction_getCustomFaultSequences(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        List<String> sequenceList = null;

        APIProvider apiProvider = getAPIProvider(thisObj);

        if (args == null || args.length >= 3) {
            String apiName = (String) args[0];
            String apiVersion = (String) args[1];
            String provider = (String) args[2];

            if (provider != null) {
                provider = APIUtil.replaceEmailDomain(provider);
            }
            APIIdentifier apiIdentifier = new APIIdentifier(provider, apiName, apiVersion);

            sequenceList = apiProvider.getCustomFaultSequences(apiIdentifier);
        } else {
            sequenceList = apiProvider.getCustomFaultSequences();
        }

        NativeArray myn = new NativeArray(0);
        if (sequenceList == null) {
            return null;
        } else {
            for (int i = 0; i < sequenceList.size(); i++) {
                myn.put(i, myn, sequenceList.get(i));
            }
            return myn;
        }
    }

    public static boolean jsFunction_isSynapseGateway(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        APIProvider provider = getAPIProvider(thisObj);
        return provider.isSynapseGateway();
    }

    public static boolean jsFunction_updateExternalAPIStores(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        boolean updated = false;
        boolean isTenantFlowStarted = false;

        NativeObject apiData = (NativeObject) args[0];
        String provider = String.valueOf(apiData.get("provider", apiData));
        if (provider != null) {
            provider = APIUtil.replaceEmailDomain(provider);
        }
        String name = (String) apiData.get("apiName", apiData);
        String version = (String) apiData.get("version", apiData);

        try {
            String tenantDomain = MultitenantUtils.getTenantDomain(APIUtil.replaceEmailDomainBack(provider));
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                isTenantFlowStarted = true;
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
            }

            APIProvider apiProvider = getAPIProvider(thisObj);

            APIIdentifier apiId = new APIIdentifier(provider, name, version);
            API api = apiProvider.getAPI(apiId);
            //Getting selected external API stores from UI and publish API to them.
            NativeArray externalAPIStores = (NativeArray) apiData.get("externalAPIStores", apiData);
            int tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                    .getTenantId(tenantDomain);
            //Check if no external APIStore selected from UI
            if (externalAPIStores != null) {
                Set<APIStore> inputStores = new HashSet<APIStore>();
                for (Object store : externalAPIStores) {
                    inputStores.add(APIUtil.getExternalAPIStore((String) store, tenantId));
                }
                Set<String> versions = apiProvider.getAPIVersions(provider, name);
                APIVersionStringComparator comparator = new APIVersionStringComparator();
                boolean apiOlderVersionExist = false;
                for (String tempVersion : versions) {
                    if (comparator.compare(tempVersion, version) < 0) {
                        apiOlderVersionExist = true;
                        break;
                    }
                }
                updated = apiProvider.updateAPIsInExternalAPIStores(api, inputStores, apiOlderVersionExist);

            }
            return updated;
        } catch (UserStoreException e) {
            handleException("Error while updating external api stores", e);
            return false;
        } finally {
            if (isTenantFlowStarted) {
                PrivilegedCarbonContext.endTenantFlow();
            }
        }
    }

    public static String jsFunction_getAPIStoreURL(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {

        APIManagerConfiguration config = HostObjectComponent.getAPIManagerConfiguration();

        //if a tenant is passed return the tenant store url
        if (args != null && args.length > 0 && args[0] != null) {
            String tenantDomain = args[0].toString();
            APIProvider apiProvider = getAPIProvider(thisObj);
            Map<String, String> domains = apiProvider.getTenantDomainMappings(tenantDomain,
                    APIConstants.API_DOMAIN_MAPPINGS_STORE);
            if (domains != null && domains.size() != 0) {
                Iterator entries = domains.entrySet().iterator();
                while (entries.hasNext()) {
                    Map.Entry thisEntry = (Map.Entry) entries.next();
                    return "https://" + thisEntry.getValue();
                }
            }
        }

        if (config != null) {
            return config.getFirstProperty(APIConstants.API_STORE_URL);
        } else {
            return null;
        }
    }

    public static boolean jsFunction_isDataPublishingEnabled(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {
        return HostObjectUtils.checkDataPublishingEnabled();
    }

    public static boolean jsFunction_showAPIStoreURL(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) {

        APIManagerConfiguration config = HostObjectComponent.getAPIManagerConfiguration();

        return config != null
                && Boolean.parseBoolean(config.getFirstProperty(APIConstants.SHOW_API_STORE_URL_FROM_PUBLISHER));
    }

    public static boolean jsFunction_showAPIDocVisibility(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) {

        APIManagerConfiguration config = HostObjectComponent.getAPIManagerConfiguration();

        return config != null && Boolean
                .parseBoolean(config.getFirstProperty(APIConstants.API_PUBLISHER_ENABLE_API_DOC_VISIBILITY_LEVELS));

    }

    /**
     * Evaluate HTTP end-point URI to validate path parameter and query
     * parameter formats<br>
     * Sample URI format<br>
     * http[s]//[www.]anyhost[.com][:port]/{uri.var.param}?param1=value&param2={uri.var.value}
     *
     * @param endpointConfig JSON representation of end-point configuration.
     * @return true if valid URI
     * @throws APIManagementException If the endpointConfig is invalid or URI is invalid
     */
    private static boolean validateEndpointURI(String endpointConfig) throws APIManagementException {
        if (endpointConfig != null) {
            try {
                JSONParser parser = new JSONParser();
                JSONObject jsonObject = (JSONObject) parser.parse(endpointConfig);
                Object epType = jsonObject.get("endpoint_type");

                if (StringUtils.isEmpty(ObjectUtils.toString(epType))) {
                    handleException("No endpoint type defined.");

                } else if (epType instanceof String && "http".equals(epType)) {
                    // extract production uri from config
                    Object prodEPs = jsonObject.get("production_endpoints");
                    Object sandEPs = jsonObject.get("sandbox_endpoints");

                    if (prodEPs == null && sandEPs == null) {
                        handleException(
                                "At least one endpoint from Production Endpoint or Sandbox Endpoint must be defined.");
                    }
                    if (prodEPs instanceof JSONObject) {
                        Object url = ((JSONObject) prodEPs).get("url");//check whether the URL is null or not

                        if (StringUtils.isBlank(ObjectUtils.toString(url))) {
                            handleException("URL of production Endpoint is not defined.");
                        }
                        if (url instanceof String && !isValidURI(url.toString())) {
                            handleException("Invalid Production Endpoint URI. Please refer HTTP Endpoint "
                                    + "documentation of the WSO2 ESB for details.");
                        }
                    }
                    // extract sandbox uri from config
                    if (sandEPs instanceof JSONObject) {
                        Object url = ((JSONObject) sandEPs).get("url");

                        if (StringUtils.isBlank(ObjectUtils.toString(url))) {
                            handleException("URL of sandbox Endpoint is not defined.");
                        }
                        if (url instanceof String && !isValidURI(url.toString())) {
                            handleException("Invalid Sandbox Endpoint URI. Please refer HTTP Endpoint "
                                    + "documentation of the WSO2 ESB for details.");
                        }
                    }
                }
            } catch (ParseException e) {
                handleException("Invalid Endpoint config", e);
            }
        }
        return true;
    }

    /**
     * This method returns whether the given url is contain valid uri params or not
     *
     * @param url URL to be validated
     * @return true if URI doesn't contain params or contains valid params
     */
    private static boolean isValidURI(String url) {
        boolean isInvalid = false;
        // validate only if uri contains { or }
        if (url != null && (url.contains("{") || url.contains("}"))) {
            // check { and } are matched or not. otherwise invalid
            int startCount = 0, endCount = 0;
            for (char c : url.toCharArray()) {
                if (c == '{') {
                    startCount++;
                } else if (c == '}') {
                    endCount++;
                }
                // this check guarantee the order of '{' and '}'. Ex: {uri.var.name} not }uri.var.name{
                if (endCount > startCount) {
                    isInvalid = true;
                    break;
                }
            }
            // continue only if the matching no of brackets are found. otherwise invalid
            if (startCount == endCount) {
                // extract content including { } brackets
                Matcher pathParamMatcher = pathParamExtractorPattern.matcher(url);
                while (pathParamMatcher.find()) {
                    // validate the format of { } content
                    Matcher formatMatcher = pathParamValidatorPattern.matcher(pathParamMatcher.group());
                    if (!formatMatcher.matches()) {
                        isInvalid = true;
                        break;
                    }
                }
            } else {
                isInvalid = true;
            }
        }
        return !isInvalid;
    }

    /**
     * Validate the backend by sending HTTP HEAD
     *
     * @param urlVal - backend URL
     * @param invalidStatusCodesRegex - Regex for the invalid status code
     * @return - status of HTTP HEAD Request to backend
     */
    private static NativeObject sendHttpHEADRequest(String urlVal, String invalidStatusCodesRegex) {

        boolean isConnectionError = true;
        String response = null;

        NativeObject data = new NativeObject();

        HttpClient client = new DefaultHttpClient();
        HttpHead head = new HttpHead(urlVal);
        client.getParams().setParameter("http.socket.timeout", 4000);
        client.getParams().setParameter("http.connection.timeout", 4000);

        if (System.getProperty(APIConstants.HTTP_PROXY_HOST) != null
                && System.getProperty(APIConstants.HTTP_PROXY_PORT) != null) {
            if (log.isDebugEnabled()) {
                log.debug("Proxy configured, hence routing through configured proxy");
            }
            String proxyHost = System.getProperty(APIConstants.HTTP_PROXY_HOST);
            String proxyPort = System.getProperty(APIConstants.HTTP_PROXY_PORT);
            client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
                    new HttpHost(proxyHost, Integer.parseInt(proxyPort)));
        }

        try {
            HttpResponse httpResponse = client.execute(head);
            String statusCode = String.valueOf(httpResponse.getStatusLine().getStatusCode());
            String reasonPhrase = String.valueOf(httpResponse.getStatusLine().getReasonPhrase());
            //If the endpoint doesn't match the regex which specify the invalid status code, it will return success.
            if (!statusCode.matches(invalidStatusCodesRegex)) {
                if (log.isDebugEnabled() && statusCode.equals(String.valueOf(HttpStatus.SC_METHOD_NOT_ALLOWED))) {
                    log.debug("Endpoint doesn't support HTTP HEAD");
                }
                response = "success";
                isConnectionError = false;

            } else {
                //This forms the real backend response to be sent to the client
                data.put("statusCode", data, statusCode);
                data.put("reasonPhrase", data, reasonPhrase);
                response = "";
                isConnectionError = false;
            }
        } catch (IOException e) {
            // sending a default error message.
            log.error("Error occurred while connecting to backend : " + urlVal + ", reason : " + e.getMessage(), e);
            String[] errorMsg = e.getMessage().split(": ");
            if (errorMsg.length > 1) {
                response = errorMsg[errorMsg.length - 1]; //This is to get final readable part of the error message in the exception and send to the client
                isConnectionError = false;
            }
        } finally {
            client.getConnectionManager().shutdown();
        }
        data.put("response", data, response);
        data.put("isConnectionError", data, isConnectionError);
        return data;
    }

    /**
     * retrieves active tenant domains and return true or false to display private
     * visibility
     *
     * @return boolean true If display private visibility
     */
    public static boolean jsFunction_isMultipleTenantsAvailable() {
        int tenantsDomainSize;
        Object cacheObj = Caching.getCacheManager(APIConstants.API_MANAGER_CACHE_MANAGER)
                .getCache(APIConstants.APIPROVIDER_HOSTCACHE).get(APIConstants.TENANTCOUNT_CACHEKEY);
        //if tenantDomainSize is not in the cache, Then the cache object is null
        if (cacheObj == null) {
            tenantsDomainSize = 0;
        } else {
            tenantsDomainSize = Integer.parseInt(cacheObj.toString());
        }
        //if there only super tenant in the system, tenantDomainSize is 1
        if (tenantsDomainSize < 2) {
            try {
                Set<String> tenantDomains = APIUtil.getActiveTenantDomains();
                //if there is more than than one tenant
                if (tenantDomains.size() > 1) {
                    Caching.getCacheManager(APIConstants.API_MANAGER_CACHE_MANAGER)
                            .getCache(APIConstants.APIPROVIDER_HOSTCACHE)
                            .put(APIConstants.TENANTCOUNT_CACHEKEY, String.valueOf(tenantDomains.size()));
                    return true;
                } else {
                    return false;
                }
            } catch (UserStoreException e) {
                /*If there are errors in getting active tenant domains from user store,
                 Minimum privileges are allocated to the user
                */
                log.error("Errors in getting active tenants form UserStore " + e.getMessage(), e);
                return false;
            }
        } else {
            return true;
        }
    }

    /*
    * here return boolean with checking all objects in array is string
    */
    public static boolean isStringArray(Object[] args) {
        //        int argsCount = args.length;
        for (Object arg : args) {
            if (!(arg instanceof String)) {
                return false;
            }
        }
        return true;

    }

    /**
     * This method is to Download API-DOCS from APIPublisher
     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return NativeObject that contains Input stream of Downloaded File
     * @throws APIManagementException Wrapped exception by org.wso2.carbon.apimgt.api.APIManagementException
     */
    public static NativeObject jsFunction_getDocument(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws ScriptException, APIManagementException {
        if (args == null || args.length != 2 || !isStringArray(args)) {
            handleException("Invalid input parameters expected resource Url and tenantDomain");
        }
        NativeObject data = new NativeObject();

        String username = ((APIProviderHostObject) thisObj).getUsername();
        // Set anonymous user if no user is login to the system
        if (username == null) {
            username = APIConstants.END_USER_ANONYMOUS;
        }
        String resource = (String) args[1];
        String tenantDomain = (String) args[0];
        Map<String, Object> docResourceMap = APIUtil.getDocument(username, resource, tenantDomain);
        if (!docResourceMap.isEmpty()) {
            data.put("Data", data, cx.newObject(thisObj, "Stream", new Object[] { docResourceMap.get("Data") }));
            data.put("contentType", data, docResourceMap.get("contentType"));
            data.put("name", data, docResourceMap.get("name"));
        } else {
            handleException("Resource couldn't found for " + resource);
        }
        return data;
    }

    /**
     * This method is to functionality of get list of environments that list in api-manager.xml
     *
     * @param cx      Rhino context
     * @param thisObj Scriptable object
     * @param args    Passing arguments
     * @param funObj  Function object
     * @return list of environments with details of environments
     */
    public static NativeArray jsFunction_getEnvironments(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) {
        NativeArray myn = new NativeArray(1);
        APIManagerConfiguration config = ServiceReferenceHolder.getInstance().getAPIManagerConfigurationService()
                .getAPIManagerConfiguration();
        Map<String, Environment> environments = config.getApiGatewayEnvironments();
        int i = 0;
        if (environments != null) {
            for (Environment environment : environments.values()) {
                NativeObject row = new NativeObject();
                row.put("name", row, environment.getName());
                row.put("description", row, environment.getDescription());
                row.put("type", row, environment.getType());
                row.put("serverURL", row, environment.getServerURL());
                row.put("apiConsole", row, environment.isShowInConsole());
                myn.put(i, myn, row);
                i++;
            }
        }
        return myn;
    }

    public static String jsFunction_isScopeExist(Context cx, Scriptable thisObj, Object[] args, Function funObj)
            throws APIManagementException {
        Boolean scopeExist = false;
        if (args != null && isStringValues(args)) {
            String scopeKey = (String) args[0];
            String username = (String) args[1];

            if (!APIUtil.isWhiteListedScope(scopeKey)) {
                String tenantDomain = MultitenantUtils.getTenantDomain(username);
                //update permission cache before validate user
                int tenantId = -1234;
                try {
                    tenantId = ServiceReferenceHolder.getInstance().getRealmService().getTenantManager()
                            .getTenantId(tenantDomain);
                } catch (UserStoreException e) {
                    handleException("Error while reading tenant information ", e);
                }

                APIProvider apiProvider = getAPIProvider(thisObj);

                try {
                    scopeExist = apiProvider.isScopeKeyExist(scopeKey, tenantId);
                } catch (APIManagementException e) {
                    handleException("Error from registry while checking the input context is already exist", e);
                }
            }
        } else {
            handleException("Input context value is null");
        }
        return scopeExist.toString();
    }

    /**
     * @param failedGateways map of failed environments
     * @return json string of input map
     */
    private static String createFailedGatewaysAsJsonString(Map<String, List<String>> failedGateways) {
        String failedJson = "{\"PUBLISHED\" : \"\" ,\"UNPUBLISHED\":\"\"}";
        if (failedGateways != null) {
            if (!failedGateways.isEmpty()) {
                StringBuilder failedToPublish = new StringBuilder();
                StringBuilder failedToUnPublish = new StringBuilder();
                for (String environmentName : failedGateways.get("PUBLISHED")) {
                    failedToPublish.append(environmentName + ",");
                }
                for (String environmentName : failedGateways.get("UNPUBLISHED")) {
                    failedToUnPublish.append(environmentName + ",");
                }
                if (!"".equals(failedToPublish.toString())) {
                    failedToPublish.deleteCharAt(failedToPublish.length() - 1);
                }
                if (!"".equals(failedToUnPublish.toString())) {
                    failedToUnPublish.deleteCharAt(failedToUnPublish.length() - 1);
                }
                failedJson = "{\"PUBLISHED\" : \"" + failedToPublish.toString() + "\" ,\"UNPUBLISHED\":\""
                        + failedToUnPublish.toString() + "\"}";
            }
        }
        return failedJson;
    }

    public static String userAgentParser(String userAgent) {
        String userBrowser;
        if (userAgent.contains("Chrome")) {
            userBrowser = "Chrome";
        } else if (userAgent.contains("Firefox")) {
            userBrowser = "Firefox";
        } else if (userAgent.contains("Opera")) {
            userBrowser = "Opera";
        } else if (userAgent.contains("MSIE")) {
            userBrowser = "Internet Explorer";
        } else {
            userBrowser = "Other";
        }
        return userBrowser;
    }

    /**
     * Url validator, Allow any url with https and http.
     * Allow any url without fully qualified domain
     *
     * @param url Url as string
     * @return boolean type stating validated or not
     */
    private static boolean isURL(String url) {
        Pattern pattern = Pattern.compile("^(http|https)://(.)+", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(url);
        return matcher.matches();
    }

    public static NativeObject jsFunction_getAllPaginatedAPIs(Context cx, Scriptable thisObj, Object[] args,
            Function funObj) throws APIManagementException {

        APIProvider provider = getAPIProvider(thisObj);
        String tenantDomain;

        if (args[0] != null) {
            tenantDomain = (String) args[0];
        } else {
            tenantDomain = org.wso2.carbon.base.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME;
        }

        int start = Integer.parseInt((String) args[1]);
        int end = Integer.parseInt((String) args[2]);

        return getPaginatedAPIs(provider, tenantDomain, start, end, thisObj);

    }

    private static NativeObject getPaginatedAPIs(APIProvider apiProvider, String tenantDomain, int start, int end,
            Scriptable thisObj) throws APIManagementException {

        List<API> apiList;
        Map<String, Object> resultMap;
        NativeArray myn = new NativeArray(0);
        NativeObject result = new NativeObject();
        boolean isTenantFlowStarted = false;
        try {
            if (tenantDomain != null && !MultitenantConstants.SUPER_TENANT_DOMAIN_NAME.equals(tenantDomain)) {
                PrivilegedCarbonContext.startTenantFlow();
                PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(tenantDomain, true);
                isTenantFlowStarted = true;
            }
            resultMap = apiProvider.getAllPaginatedAPIs(tenantDomain, start, end);

        } finally {
            if (isTenantFlowStarted) {

                PrivilegedCarbonContext.endTenantFlow();
            }
        }
        if (resultMap != null) {
            apiList = (List<API>) resultMap.get("apis");
            if (apiList != null) {
                Iterator it = apiList.iterator();
                int i = 0;
                while (it.hasNext()) {
                    NativeObject row = new NativeObject();
                    Object apiObject = it.next();
                    API api = (API) apiObject;
                    APIIdentifier apiIdentifier = api.getId();
                    row.put("name", row, apiIdentifier.getApiName());
                    row.put("version", row, apiIdentifier.getVersion());
                    row.put("provider", row, APIUtil.replaceEmailDomainBack(apiIdentifier.getProviderName()));
                    row.put("status", row, checkValue(api.getStatus().toString()));
                    row.put("thumb", row, getWebContextRoot(api.getThumbnailUrl()));
                    row.put("subs", row, getSubscriberCount(apiIdentifier, thisObj));
                    myn.put(i, myn, row);
                    i++;
                }
                result.put("apis", result, myn);
                result.put("totalLength", result, resultMap.get("totalLength"));
                result.put("isMore", result, resultMap.get("isMore"));
            }
        }
        return result;
    }

    private static String addSecurityDef(String spec, Set<Scope> scopes) {

        List<String> scopeNames = new ArrayList<String>();
        Swagger swagger = new SwaggerParser().parse(spec);
        Map<String, Path> paths = swagger.getPaths();
        Operation operation;
        APIManagerConfiguration config = org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder.getInstance()
                .getAPIManagerConfigurationService().getAPIManagerConfiguration();
        String revokeUrl = config.getFirstProperty(APIConstants.REVOKE_API_URL);
        String tokenUrl = revokeUrl != null ? revokeUrl.replace("revoke", "token") : null;
        tokenUrl = tokenUrl != null ? tokenUrl.replace("'", "") : null;

        OAuthAdminService oAuthAdminService = new OAuthAdminService();
        String[] allowedGrantTypesArr = oAuthAdminService.getAllowedGrantTypes();
        String allowedGrantTypes = StringUtils.join(allowedGrantTypesArr, ",");

        APISecuritySchemeDefinition apiSecuritySchemeDefinition = new APISecuritySchemeDefinition();
        apiSecuritySchemeDefinition.setType("oauth2");
        apiSecuritySchemeDefinition.setAuthorizationUrl(tokenUrl);

        apiSecuritySchemeDefinition.setFlow(allowedGrantTypes);

        for (Scope s : scopes) {
            scopeNames.add(s.getName());
            apiSecuritySchemeDefinition.setScopes(s.getName(), s.getDescription());
        }

        String securityName = swagger.getInfo().getTitle().toLowerCase() + "_oauth";

        for (Map.Entry<String, Path> entry : paths.entrySet()) {
            operation = paths.get(entry.getKey()).getGet();
            if (operation != null) {
                paths.get(entry.getKey()).getGet().setSecurity(null);
                paths.get(entry.getKey()).getGet().addSecurity(securityName, scopeNames);
            }

            operation = paths.get(entry.getKey()).getPatch();
            if (operation != null) {
                paths.get(entry.getKey()).getPatch().setSecurity(null);
                paths.get(entry.getKey()).getPatch().addSecurity(securityName, scopeNames);
            }

            operation = paths.get(entry.getKey()).getDelete();
            if (operation != null) {
                paths.get(entry.getKey()).getDelete().setSecurity(null);
                paths.get(entry.getKey()).getDelete().addSecurity(securityName, scopeNames);
            }

            operation = paths.get(entry.getKey()).getHead();
            if (operation != null) {
                paths.get(entry.getKey()).getHead().setSecurity(null);
                paths.get(entry.getKey()).getHead().addSecurity(securityName, scopeNames);
            }

            operation = paths.get(entry.getKey()).getPost();
            if (operation != null) {
                paths.get(entry.getKey()).getPost().setSecurity(null);
                paths.get(entry.getKey()).getPost().addSecurity(securityName, scopeNames);
            }

            operation = paths.get(entry.getKey()).getPut();
            if (operation != null) {
                paths.get(entry.getKey()).getPut().setSecurity(null);
                paths.get(entry.getKey()).getPut().addSecurity(securityName, scopeNames);
            }

            operation = paths.get(entry.getKey()).getOptions();
            if (operation != null) {
                paths.get(entry.getKey()).getOptions().setSecurity(null);
                paths.get(entry.getKey()).getOptions().addSecurity(securityName, scopeNames);
            }

        }

        Map<String, SecuritySchemeDefinition> securityDefMap = new HashMap<String, SecuritySchemeDefinition>();

        securityDefMap.put(securityName, apiSecuritySchemeDefinition);

        swagger.setSecurityDefinitions(securityDefMap);

        swagger.setPaths(paths);
        return Json.pretty(swagger);
    }

}