All Downloads are FREE. Search and download functionalities are using the official Maven repository.

esa.restlight.server.util.MappingUtils Maven / Gradle / Ivy

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

import esa.commons.StringUtils;
import esa.restlight.core.method.HttpMethod;
import esa.restlight.core.util.MediaType;
import esa.restlight.server.route.Mapping;
import esa.restlight.server.route.impl.MappingImpl;
import esa.restlight.server.route.predicate.ConsumesPredicate;
import esa.restlight.server.route.predicate.HeadersPredicate;
import esa.restlight.server.route.predicate.ProducesPredicate;
import io.netty.handler.codec.http.HttpHeaderNames;

import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

public class MappingUtils {

    /**
     * Combines given child {@link Mapping} into the parent {@link Mapping}.
     *
     * @param parent parent mapping
     * @param child  child mapping
     * @return combined
     */
    public static Mapping combine(Mapping parent, Mapping child) {
        if (parent == null) {
            return child;
        }
        if (child == null) {
            return parent;
        }
        MappingImpl mapping = Mapping.mapping()
                .name(StringUtils.nonEmptyOrElse(child.name(), parent.name()))
                .path(combinePaths(parent.path(), child.path()))
                .method(removeDuplicate(parent.method(), child.method(), new HttpMethod[0]))
                .params(removeDuplicateString(parent.params(), child.params()));

        String[] parentHeaders = parent.headers();
        if (parseConsumeExpressions(child.consumes(), child.headers()).isEmpty()) {
            // could not parse any consumes from child mapping
            // so we use parent consumes and parent headers
            mapping = mapping.consumes(parent.consumes());
        } else {
            // parsed consumes from child mapping, so we need to ignore the parent consumes and content-type in
            // parent headers.
            mapping = mapping.consumes(child.consumes());
            parentHeaders = removeConsumes(parentHeaders);
        }

        if (parseProduceExpressions(child.produces(), child.headers()).isEmpty()) {
            // could not parse any produces from child mapping
            // so we use parent consumes and parent headers
            mapping = mapping.produces(parent.produces());
        } else {
            mapping = mapping.produces(child.produces());
            parentHeaders = removeAccepts(parentHeaders);
        }
        // merge parent headers and child headers
        return mapping.headers(removeDuplicateString(parentHeaders, child.headers()));
    }


    /**
     * Parses given consumes predicates strings and headers predicates strings to {@link
     * ConsumesPredicate.Expression}.
     *
     * @param consumes consumes
     * @param headers  headers
     * @return parsed expressions
     */
    public static Set parseConsumeExpressions(String[] consumes,
                                                                            String[] headers) {
        Set result = new LinkedHashSet<>();
        if (headers != null) {
            for (String header : headers) {
                HeadersPredicate.Expression expr =
                        new HeadersPredicate.Expression(header);
                if (HttpHeaderNames.CONTENT_TYPE.contentEqualsIgnoreCase(expr.getName())) {
                    for (MediaType mediaType : MediaType.valuesOf(expr.getValue())) {
                        result.add(new ConsumesPredicate.Expression(mediaType,
                                expr.isNegated()));
                    }
                }
            }
        }
        if (consumes != null) {
            for (String consume : consumes) {
                result.add(new ConsumesPredicate.Expression(consume));
            }
        }

        return result;
    }

    /**
     * Parses given produces predicates strings and headers predicates strings to {@link
     * ProducesPredicate.Expression}.
     *
     * @param produces consumes
     * @param headers  headers
     * @return parsed expressions
     */
    public static Set parseProduceExpressions(String[] produces,
                                                                            String[] headers) {
        Set result = new LinkedHashSet<>();
        if (headers != null) {
            for (String header : headers) {
                HeadersPredicate.Expression expr =
                        new HeadersPredicate.Expression(header);
                if (HttpHeaderNames.ACCEPT.contentEqualsIgnoreCase(expr.getName()) && expr.getValue() != null) {
                    for (MediaType mediaType : MediaType.valuesOf(expr.getValue())) {
                        result.add(new ProducesPredicate.Expression(mediaType,
                                expr.isNegated()));
                    }
                }
            }
        }
        if (produces != null) {
            for (String produce : produces) {
                result.add(new ProducesPredicate.Expression(produce));
            }
        }
        return result;
    }

    /**
     * Determines whether the given components may intersect potentially.
     *
     * @param a   components a
     * @param b   components a
     * @param  component type
     * @return {@code true} if given components may intersect potentially.
     */
    public static  boolean isIntersect(T[] a, T[] b) {
        if (a == null || b == null) {
            return false;
        }
        if (a.length == 0 || b.length == 0) {
            return false;
        }
        Set set1 = new HashSet<>(Arrays.asList(a));
        Set set2 = new HashSet<>(Arrays.asList(b));
        set1.retainAll(set2);
        return !set1.isEmpty();
    }

    /**
     * Combines the paths from parent {@link Mapping}
     * 

* use the {@link PathMatcher#combine(String, String)} to combine the parent paths and current paths if the paths of * the parent and current is both present, otherwise use the paths that is present, or just padding a empty string. */ private static String[] combinePaths(String[] parentPaths, String[] childPaths) { final Set result = new LinkedHashSet<>(); if (parentPaths.length != 0 && childPaths.length != 0) { for (String pattern1 : parentPaths) { for (String pattern2 : childPaths) { result.add(PathMatcher.combine(pattern1, pattern2)); } } } else if (parentPaths.length != 0) { result.addAll(Arrays.asList(parentPaths)); } else if (childPaths.length != 0) { result.addAll(Arrays.asList(childPaths)); } else { result.add(""); } return result.toArray(new String[0]); } private static boolean isConsume(String header) { HeadersPredicate.Expression expr = new HeadersPredicate.Expression(header); return isConsume(expr); } private static boolean isAccept(String header) { HeadersPredicate.Expression expr = new HeadersPredicate.Expression(header); return isAccept(expr); } private static T[] removeDuplicate(T[] origin, T[] other, T[] target) { if (origin == null) { return other; } else if (other == null) { return origin; } Set set = new LinkedHashSet<>(Arrays.asList(origin)); set.addAll(Arrays.asList(other)); return set.toArray(target); } private static String[] removeDuplicateString(String[] origin, String[] other) { return removeDuplicate(origin, other, new String[0]); } private static String[] removeConsumes(String[] headers) { if (headers == null || headers.length == 0) { return null; } Set newHeaders = new HashSet<>(headers.length); for (String header : headers) { if (!isConsume(header)) { newHeaders.add(header); } } return newHeaders.toArray(new String[0]); } private static String[] removeAccepts(String[] headers) { if (headers == null || headers.length == 0) { return null; } Set newHeaders = new HashSet<>(headers.length); for (String header : headers) { if (!isAccept(header)) { newHeaders.add(header); } } return newHeaders.toArray(new String[0]); } private static boolean isConsume(HeadersPredicate.Expression expr) { return HttpHeaderNames.CONTENT_TYPE.contentEqualsIgnoreCase(expr.getName()); } private static boolean isAccept(HeadersPredicate.Expression expr) { return HttpHeaderNames.ACCEPT.contentEqualsIgnoreCase(expr.getName()) && expr.getValue() != null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy