org.wso2.carbon.apimgt.core.util.APIUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.apimgt.core.util.APIUtils.java

Source

/*
 *   Copyright (c) 2016, 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.core.util;

import io.swagger.models.HttpMethod;
import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wso2.carbon.apimgt.core.exception.APIManagementException;
import org.wso2.carbon.apimgt.core.exception.ExceptionCodes;
import org.wso2.carbon.apimgt.core.models.API;
import org.wso2.carbon.apimgt.core.models.CompositeAPI;
import org.wso2.carbon.apimgt.core.models.Scope;
import org.wso2.carbon.apimgt.core.models.UriTemplate;
import org.wso2.carbon.apimgt.core.models.policy.APIPolicy;
import org.wso2.carbon.apimgt.core.models.policy.Policy;
import org.wso2.carbon.lcm.core.impl.LifecycleState;

import java.time.Duration;
import java.time.temporal.Temporal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;

/**
 * Class for all utility methods
 */
public class APIUtils {

    private static final Logger log = LoggerFactory.getLogger(APIUtils.class);

    /**
     * Checks if debug log is enabled and logs the message
     *
     * @param msg Message to be logged
     * @param log Logger to be used to log
     */
    public static void logDebug(String msg, Logger log) {
        if (log.isDebugEnabled()) {
            log.debug(msg);
        }
    }

    /**
     * Find scope object in a set based on the key
     *
     * @param scopes - Set of scopes
     * @param key    - Key to search with
     * @return Scope - scope object
     */
    public static Scope findScopeByKey(Set<Scope> scopes, String key) {
        for (Scope scope : scopes) {
            if (scope.getKey().equals(key)) {
                return scope;
            }
        }
        return null;
    }

    /**
     * Returns a map of API availability tiers of the tenant as defined in the underlying governance
     * registry.
     *
     * @param policyType Policy Type
     * @return a Map of tier names and Tier objects - possibly empty
     * @throws APIManagementException if an error occurs when loading tiers from the registry
     */
    public static Map<String, Policy> getPolicies(int policyType) throws APIManagementException {
        return null;
    }

    public static Policy getDefaultAPIPolicy() {
        return new APIPolicy(APIMgtConstants.DEFAULT_API_POLICY);
    }

    /**
     * Validate the API object
     * @param api API object
     * @throws APIManagementException if mandatory field is not set
     */
    public static void validate(API api) throws APIManagementException {
        if (StringUtils.isEmpty(api.getId())) {
            throw new APIManagementException("Couldn't find UUID of API");
        }
        if (StringUtils.isEmpty(api.getName())) {
            throw new APIManagementException("Couldn't find Name of API ");
        }
        if (StringUtils.isEmpty(api.getVersion())) {
            throw new APIManagementException("Couldn't find Version of API ");
        }
    }

    /**
     * Validate the CompositeAPI object
     * @param api CompositeAPI object
     * @throws APIManagementException if mandatory field is not set
     */
    public static void validate(CompositeAPI api) throws APIManagementException {
        if (StringUtils.isEmpty(api.getId())) {
            throw new APIManagementException("Couldn't find UUID of CompositeAPI");
        }
        if (StringUtils.isEmpty(api.getName())) {
            throw new APIManagementException("Couldn't find Name of CompositeAPI ");
        }
        if (StringUtils.isEmpty(api.getVersion())) {
            throw new APIManagementException("Couldn't find Version of CompositeAPI ");
        }
    }

    /**
     * Checks String lists for equality independent of the order of elements in the lists.
     *
     * Note that order of the elements in the lists will be changed as a result of sorting,
     * but this is not a concern usually since the order does not matter.
     * @param list1 String list
     * @param list2 String list
     * @return true if elements in lists are equal irrespective of order
     */
    public static boolean isListsEqualIgnoreOrder(List<String> list1, List<String> list2) {
        if (list1 == null && list2 == null) {
            return true;
        }

        if (list1 == null || list2 == null || list1.size() != list2.size()) {
            return false;
        }

        // Sort lists so that the order of elements don't affect the equal check.
        // Note that order of the elements in the lists will be changed as a result but this is not a concern since
        // the order does not matter
        Collections.sort(list1);
        Collections.sort(list2);
        return list1.equals(list2);
    }

    /**
     * Checks generic lists for equality independent of the order of elements in the lists.
     *
     * Note that order of the elements in the lists will be changed as a result of sorting,
     * but this is not a concern usually since the order does not matter.
     * @param list1 T list
     * @param list2 T list
     * @param comparator Comparator class
     * @return true if elements in lists are equal irrespective of order
     */
    public static <T> boolean isListsEqualIgnoreOrder(List<T> list1, List<T> list2, Comparator<T> comparator) {
        if (list1 == null && list2 == null) {
            return true;
        }

        if (list1 == null || list2 == null || list1.size() != list2.size()) {
            return false;
        }

        // Sort lists so that the order of elements don't affect the equal check.
        // Note that order of the elements in the lists will be changed as a result but this is not a concern since
        // the order does not matter
        Collections.sort(list1, comparator);
        Collections.sort(list2, comparator);
        return list1.equals(list2);
    }

    public static boolean isTimeStampsEquals(Temporal date1, Temporal date2) {
        if (date1 == null && date2 == null) {
            return true;
        } else {
            return Duration.between(date1, date2).toMillis() < 1000L;
        }
    }

    @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "DM_CONVERT_CASE", justification = "Didn't need to do "
            + "as String already did internally")

    /**
     * used to generate operationId according to the uri template and http verb
     */
    public static String generateOperationIdFromPath(String path, String httpVerb) {
        //TODO need to write proper way of creating operationId
        StringTokenizer stringTokenizer = new StringTokenizer(path, "/");
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(httpVerb.toLowerCase());
        while (stringTokenizer.hasMoreElements()) {
            String part1 = stringTokenizer.nextToken();
            if (part1.contains("{")) {
                /*
                                stringBuilder.append("By" + pathParam);
                */
            } else if (part1.contains("*")) {
                stringBuilder.append(part1.replaceAll("\\*", "_star_"));
            } else {
                stringBuilder.append(part1);
            }
        }
        return stringBuilder.toString();
    }

    /**
     * Generates default URI templates to be assigned to an API
     * @return  Map of URI Templates
     */
    public static Map<String, UriTemplate> getDefaultUriTemplates() {
        Map<String, UriTemplate> uriTemplateMap = new HashMap<>();
        UriTemplate.UriTemplateBuilder uriTemplateBuilder = new UriTemplate.UriTemplateBuilder();
        uriTemplateBuilder.uriTemplate("/");
        for (String httpVerb : APIMgtConstants.SUPPORTED_HTTP_VERBS.split(",")) {
            if (!HttpMethod.OPTIONS.toString().equals(httpVerb)) {
                uriTemplateBuilder.httpVerb(httpVerb);
                uriTemplateBuilder.policy(APIUtils.getDefaultAPIPolicy());
                uriTemplateBuilder.templateId(
                        APIUtils.generateOperationIdFromPath(uriTemplateBuilder.getUriTemplate(), httpVerb));
                uriTemplateMap.put(uriTemplateBuilder.getTemplateId(), uriTemplateBuilder.build());
            }
        }

        return uriTemplateMap;
    }

    public static Map<String, UriTemplate> getMergedUriTemplates(Map<String, UriTemplate> oldUriTemplateMap,
            Map<String, UriTemplate> updatedUriTemplateMap) {
        Map<String, UriTemplate> uriTemplateMap = new HashMap<>();
        for (UriTemplate uriTemplate : updatedUriTemplateMap.values()) {
            if (oldUriTemplateMap.containsKey(uriTemplate.getTemplateId())) {
                uriTemplateMap.put(uriTemplate.getTemplateId(), oldUriTemplateMap.get(uriTemplate.getTemplateId()));
            } else {
                uriTemplateMap.put(uriTemplate.getTemplateId(), uriTemplate);
            }
        }
        return uriTemplateMap;
    }

    /**
     * Validate lifecycle state transition is valid from one state to other
     * @param lifecycleState Lifecycle state object
     * @param nextState target lifecycle state
     * @return true if target state is valid
     */
    public static boolean validateTargetState(LifecycleState lifecycleState, String nextState) {
        return lifecycleState.getAvailableTransitionBeanList().stream()
                .anyMatch(availableTransitionBean -> availableTransitionBean.getTargetState().equals(nextState));
    }

    /**
     * This method is used to construct the aggregate permission list from the aggregate permission integer value
     *
     * @param permissionValue - The aggregate permission value for the logged in user
     * @return The array containing the aggregate permissions for the logged in user
     */
    public static List<String> constructApiPermissionsListForValue(Integer permissionValue) {
        List<String> array = new ArrayList<String>();
        if ((permissionValue & APIMgtConstants.Permission.READ_PERMISSION) != 0) {
            array.add(APIMgtConstants.Permission.READ);
        }
        if ((permissionValue & APIMgtConstants.Permission.UPDATE_PERMISSION) != 0) {
            array.add(APIMgtConstants.Permission.UPDATE);
        }
        if ((permissionValue & APIMgtConstants.Permission.DELETE_PERMISSION) != 0) {
            array.add(APIMgtConstants.Permission.DELETE);
        }
        if ((permissionValue & APIMgtConstants.Permission.MANAGE_SUBSCRIPTION_PERMISSION) != 0) {
            array.add(APIMgtConstants.Permission.MANAGE_SUBSCRIPTION);
        }
        return array;
    }

    /**
     * This method returns all available roles
     *
     * @return all available roles
     */
    public static Set<String> getAllAvailableRoles() {

        //this should be a call to IS endpoint and get all the roles, we are returning a dummy list till then
        Set<String> availableRoles = new HashSet<>();
        availableRoles.add("admin");
        availableRoles.add("subscriber");
        availableRoles.add("manager");
        availableRoles.add("developer");
        availableRoles.add("lead");
        availableRoles.add(APIMgtConstants.Permission.EVERYONE_GROUP);
        return availableRoles;
    }

    /**
     * Used to get roles of a particular user
     *
     * @param username username of the person
     * @return role list of the user
     */
    public static Set<String> getAllRolesOfUser(String username) {

        //this should be a call to IS endpoint and get roles of the user, we are returning a dummy list till then
        Set<String> userRoles = new HashSet<>();
        if ("admin".equalsIgnoreCase(username)) {
            userRoles.add("admin");
            userRoles.add("comment-moderator");
            userRoles.add(APIMgtConstants.Permission.EVERYONE_GROUP);
        } else if ("subscriber".equalsIgnoreCase(username)) {
            userRoles.add("subscriber");
        } else if ("John".equalsIgnoreCase(username)) {
            userRoles.add("manager");
            userRoles.add("developer");
        } else if ("Smith".equalsIgnoreCase(username)) {
            userRoles.add("lead");
        } else if ("Alex".equalsIgnoreCase(username)) {
            userRoles.add("admin");
            userRoles.add("manager");
        }
        return userRoles;
    }

    /**
     * Check the validity of roles to be assigned to an API
     *
     * @param availableRoleList all available roles
     * @param candidateRoleList candidate roles to be assigned to the API
     * @return true if all candidate roles are eligible
     * @throws APIManagementException if the check fails
     */
    public static boolean checkAllowedRoles(Set<String> availableRoleList, Set<String> candidateRoleList)
            throws APIManagementException {

        //check if availableRoleList and candidateRoleList is not null
        if (availableRoleList != null && candidateRoleList != null) {
            if (availableRoleList.isEmpty() || candidateRoleList.isEmpty()) {
                String errorMsg = "Role list is empty.";
                log.error(errorMsg);
                throw new APIManagementException(errorMsg, ExceptionCodes.ROLES_CANNOT_BE_EMPTY);
            } else {
                //check if all roles in candidateRoleList are in availableRoleList
                if (availableRoleList.containsAll(candidateRoleList)) {
                    return true;
                } else {
                    String errorMsg = "Invalid role(s) found.";
                    log.error(errorMsg);
                    throw new APIManagementException(errorMsg, ExceptionCodes.UNSUPPORTED_ROLE);
                }
            }
        } else {
            String errorMsg = "Role(s) list is null.";
            log.error(errorMsg);
            throw new APIManagementException(errorMsg, ExceptionCodes.ROLES_CANNOT_BE_NULL);
        }
    }

    /**
     * This method will return map with role names and its permission values. This is not for an API. This is for other
     * resources of an API.
     *
     * @param permissionJsonString Permission json object a string
     * @return Map of permission values.
     * @throws ParseException If failed to parse the json string.
     */
    public static HashMap getAPIPermissionArray(String permissionJsonString) throws ParseException {

        HashMap roleNamePermissionList = new HashMap();
        JSONParser jsonParser = new JSONParser();

        JSONArray baseJsonArray = (JSONArray) jsonParser.parse(permissionJsonString);
        for (Object aBaseJsonArray : baseJsonArray) {
            JSONObject jsonObject = (JSONObject) aBaseJsonArray;
            String groupId = jsonObject.get(APIMgtConstants.Permission.GROUP_ID).toString();
            JSONArray subJsonArray = (JSONArray) jsonObject.get(APIMgtConstants.Permission.PERMISSION);
            int totalPermissionValue = 0;
            for (Object aSubJsonArray : subJsonArray) {
                if (APIMgtConstants.Permission.READ.equals(aSubJsonArray.toString().trim())) {
                    totalPermissionValue += APIMgtConstants.Permission.READ_PERMISSION;
                } else if (APIMgtConstants.Permission.UPDATE.equals(aSubJsonArray.toString().trim())) {
                    totalPermissionValue += APIMgtConstants.Permission.UPDATE_PERMISSION;
                } else if (APIMgtConstants.Permission.DELETE.equals(aSubJsonArray.toString().trim())) {
                    totalPermissionValue += APIMgtConstants.Permission.DELETE_PERMISSION;
                }
            }
            roleNamePermissionList.put(groupId, totalPermissionValue);
        }

        return roleNamePermissionList;

    }

    /**
    * Verifies that fields that cannot be changed via an API update
    * do not differ from the values in the original API
    *
    * @param apiBuilder Updated APIBuilder object
    * @param originalAPI Original API being updated
    * @throws APIManagementException If non modifiable field update is detected
    */
    public static void verifyValidityOfApiUpdate(API.APIBuilder apiBuilder, API originalAPI)
            throws APIManagementException {
        if (!originalAPI.getLifeCycleStatus().equals(apiBuilder.getLifeCycleStatus())) {
            String msg = "API " + apiBuilder.getName() + "-" + apiBuilder.getVersion() + " Couldn't update as "
                    + "the API Status cannot be changed";
            if (log.isDebugEnabled()) {
                log.debug(msg);
            }

            throw new APIManagementException(msg, ExceptionCodes.COULD_NOT_UPDATE_API);
        }

        if (!originalAPI.getName().equals(apiBuilder.getName())) {
            String msg = "API " + apiBuilder.getName() + "-" + apiBuilder.getVersion() + " update not allowed, "
                    + "the API Name cannot be changed";
            if (log.isDebugEnabled()) {
                log.debug(msg);
            }

            throw new APIManagementException(msg, ExceptionCodes.COULD_NOT_UPDATE_API);
        }

        if (!originalAPI.getContext().equals(apiBuilder.getContext())) {
            String msg = "API " + apiBuilder.getName() + "-" + apiBuilder.getVersion() + " update not allowed, "
                    + "the API Context cannot be changed";
            if (log.isDebugEnabled()) {
                log.debug(msg);
            }

            throw new APIManagementException(msg, ExceptionCodes.COULD_NOT_UPDATE_API);
        }

        if (!originalAPI.getVersion().equals(apiBuilder.getVersion())) {
            String msg = "API " + apiBuilder.getName() + "-" + apiBuilder.getVersion() + " update not allowed, "
                    + "the API Version cannot be changed";
            if (log.isDebugEnabled()) {
                log.debug(msg);
            }

            throw new APIManagementException(msg, ExceptionCodes.COULD_NOT_UPDATE_API);
        }

        if (!originalAPI.getProvider().equals(apiBuilder.getProvider())) {
            String msg = "API " + apiBuilder.getName() + "-" + apiBuilder.getVersion() + " update not allowed, "
                    + "the API Provider cannot be changed";
            if (log.isDebugEnabled()) {
                log.debug(msg);
            }

            throw new APIManagementException(msg, ExceptionCodes.COULD_NOT_UPDATE_API);
        }
    }

    /**
     * Verifies that fields that cannot be changed via an API update
     * do not differ from the values in the original API
     *
     * @param apiBuilder Updated APIBuilder object
     * @param originalAPI Original API being updated
     * @throws APIManagementException If non modifiable field update is detected
     */
    public static void verifyValidityOfApiUpdate(CompositeAPI.Builder apiBuilder, CompositeAPI originalAPI)
            throws APIManagementException {

        if (!originalAPI.getName().equals(apiBuilder.getName())) {
            String msg = "API " + apiBuilder.getName() + "-" + apiBuilder.getVersion() + " update not allowed, "
                    + "the API Name cannot be changed";
            if (log.isDebugEnabled()) {
                log.debug(msg);
            }

            throw new APIManagementException(msg, ExceptionCodes.COULD_NOT_UPDATE_API);
        }

        if (!originalAPI.getContext().equals(apiBuilder.getContext())) {
            String msg = "API " + apiBuilder.getName() + "-" + apiBuilder.getVersion() + " update not allowed, "
                    + "the API Context cannot be changed";
            if (log.isDebugEnabled()) {
                log.debug(msg);
            }

            throw new APIManagementException(msg, ExceptionCodes.COULD_NOT_UPDATE_API);
        }

        if (!originalAPI.getVersion().equals(apiBuilder.getVersion())) {
            String msg = "API " + apiBuilder.getName() + "-" + apiBuilder.getVersion() + " update not allowed, "
                    + "the API Version cannot be changed";
            if (log.isDebugEnabled()) {
                log.debug(msg);
            }

            throw new APIManagementException(msg, ExceptionCodes.COULD_NOT_UPDATE_API);
        }

        if (!originalAPI.getProvider().equals(apiBuilder.getProvider())) {
            String msg = "API " + apiBuilder.getName() + "-" + apiBuilder.getVersion() + " update not allowed, "
                    + "the API Provider cannot be changed";
            if (log.isDebugEnabled()) {
                log.debug(msg);
            }

            throw new APIManagementException(msg, ExceptionCodes.COULD_NOT_UPDATE_API);
        }
    }

    /**
     * Utility for Ip to Long convrsion
     * @param ip ip value
     * @return return long value of Ip
     */
    public static long ipToLong(String ip) {
        long ipAddressinLong = 0;
        if (ip != null) {
            //convert ipaddress into a long
            String[] ipAddressArray = ip.split("\\."); //split by "." and add to an array

            for (int i = 0; i < ipAddressArray.length; i++) {
                int power = 3 - i;
                long ipAddress = Long.parseLong(ipAddressArray[i]); //parse to long
                ipAddressinLong += ipAddress * Math.pow(256, power);
            }
        }
        return ipAddressinLong;
    }
}