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

com.yahoo.elide.jsonapi.JsonApiRequestScope Maven / Gradle / Ivy

There is a newer version: 7.1.4
Show newest version
/*
 * Copyright 2016, Yahoo Inc.
 * Licensed under the Apache License, Version 2.0
 * See LICENSE file in project root for terms.
 */
package com.yahoo.elide.jsonapi;

import com.yahoo.elide.ElideSettings;
import com.yahoo.elide.core.RequestScope;
import com.yahoo.elide.core.datastore.DataStoreTransaction;
import com.yahoo.elide.core.dictionary.EntityDictionary;
import com.yahoo.elide.core.exceptions.BadRequestException;
import com.yahoo.elide.core.filter.dialect.ParseException;
import com.yahoo.elide.core.filter.dialect.RSQLFilterDialect;
import com.yahoo.elide.core.filter.dialect.jsonapi.DefaultFilterDialect;
import com.yahoo.elide.core.filter.dialect.jsonapi.JoinFilterDialect;
import com.yahoo.elide.core.filter.dialect.jsonapi.MultipleFilterDialect;
import com.yahoo.elide.core.filter.dialect.jsonapi.SubqueryFilterDialect;
import com.yahoo.elide.core.request.EntityProjection;
import com.yahoo.elide.core.request.route.Route;
import com.yahoo.elide.core.security.User;
import com.yahoo.elide.jsonapi.models.JsonApiDocument;

import lombok.Getter;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;

/**
 * Request scope object for relaying request-related data to various subsystems.
 */
public class JsonApiRequestScope extends RequestScope {
    @Getter private final JsonApiDocument jsonApiDocument;
    @Getter private final JsonApiMapper mapper;
    @Getter private final int updateStatusCode;
    @Getter private final MultipleFilterDialect filterDialect;

    /**
     * Create a new RequestScope.
     *
     * @param route         the route
     * @param transaction   the transaction for this request
     * @param user          the user making this request
     * @param requestId     request ID
     * @param elideSettings Elide settings object
     */
    public JsonApiRequestScope(Route route,
                        DataStoreTransaction transaction,
                        User user,
                        UUID requestId,
                        ElideSettings elideSettings,
                        Function entityProjection,
                        JsonApiDocument jsonApiDocument
                        ) {
        super(route, transaction, user, requestId, elideSettings, entityProjection);
        this.jsonApiDocument = jsonApiDocument;

        JsonApiSettings jsonApiSettings = elideSettings.getSettings(JsonApiSettings.class);
        this.mapper = jsonApiSettings.getJsonApiMapper();
        this.updateStatusCode = jsonApiSettings.getUpdateStatusCode();

        List joinFilterDialects = new ArrayList<>(jsonApiSettings.getJoinFilterDialects());
        List subqueryFilterDialects = new ArrayList<>(
                jsonApiSettings.getSubqueryFilterDialects());

        EntityDictionary entityDictionary = elideSettings.getEntityDictionary();

        if (joinFilterDialects.isEmpty()) {
            joinFilterDialects.add(new DefaultFilterDialect(entityDictionary));
            joinFilterDialects.add(RSQLFilterDialect.builder().dictionary(entityDictionary).build());
        }

        if (subqueryFilterDialects.isEmpty()) {
            subqueryFilterDialects.add(new DefaultFilterDialect(entityDictionary));
            subqueryFilterDialects.add(RSQLFilterDialect.builder().dictionary(entityDictionary).build());
        }

        this.filterDialect = new MultipleFilterDialect(joinFilterDialects,
                subqueryFilterDialects);

        Map> queryParams = getRoute().getParameters();
        String path = route.getPath();
        String apiVersion = route.getApiVersion();

        if (!queryParams.isEmpty()) {

            /* Extract any query param that starts with 'filter' */
            Map> filterParams = getFilterParams(queryParams);

            String errorMessage = "";
            if (! filterParams.isEmpty()) {

                /* First check to see if there is a global, cross-type filter */
                try {
                    globalFilterExpression = filterDialect.parseGlobalExpression(path, filterParams, apiVersion);
                } catch (ParseException e) {
                    errorMessage = e.getMessage();
                }

                /* Next check to see if there is are type specific filters */
                try {
                    expressionsByType.putAll(filterDialect.parseTypedExpression(path, filterParams, apiVersion));
                } catch (ParseException e) {

                    /* If neither dialect parsed, report the last error found */
                    if (globalFilterExpression == null) {

                        if (errorMessage.isEmpty()) {
                            errorMessage = e.getMessage();
                        } else if (! errorMessage.equals(e.getMessage())) {

                            /* Combine the two different messages together */
                            errorMessage = errorMessage + "\n" + e.getMessage();
                        }

                        throw new BadRequestException(errorMessage, e);
                    }
                }
            }
        }
    }

    /**
     * Special copy constructor for use by PatchRequestScope.
     *
     * @param route             the route
     * @param jsonApiDocument   the json api document
     * @param outerRequestScope the outer request scope
     */
    protected JsonApiRequestScope(Route route, JsonApiDocument jsonApiDocument, JsonApiRequestScope outerRequestScope) {
        super(outerRequestScope);
        this.route = route;
        this.jsonApiDocument = jsonApiDocument;
        setEntityProjection(new EntityProjectionMaker(outerRequestScope.getElideSettings().getEntityDictionary(), this)
                .parsePath(this.route.getPath()));
        this.updateStatusCode = outerRequestScope.getUpdateStatusCode();
        this.mapper = outerRequestScope.getMapper();
        this.filterDialect = outerRequestScope.getFilterDialect();
    }

    /**
     * Extracts any query params that start with 'filter'.
     * @param queryParams request query params
     * @return extracted filter params
     */
    private static Map> getFilterParams(Map> queryParams) {
        Map> returnMap = new LinkedHashMap<>();

        queryParams.entrySet()
                .stream()
                .filter(entry -> entry.getKey().startsWith("filter"))
                .forEach(entry -> returnMap.put(entry.getKey(), entry.getValue()));
        return returnMap;
    }

    /**
     * Returns a mutable {@link JsonApiRequestScopeBuilder} for building {@link JsonApiRequestScope}.
     *
     * @return the builder
     */
    public static JsonApiRequestScopeBuilder builder() {
        return new JsonApiRequestScopeBuilder();
    }

    /**
     * A mutable builder for building {@link JsonApiRequestScope}.
     */
    public static class JsonApiRequestScopeBuilder extends RequestScopeBuilder {
        protected JsonApiDocument jsonApiDocument;

        public JsonApiRequestScopeBuilder jsonApiDocument(JsonApiDocument jsonApiDocument) {
            this.jsonApiDocument = jsonApiDocument;
            return this;
        }

        @Override
        public JsonApiRequestScope build() {
            applyDefaults();
            return new JsonApiRequestScope(this.route, this.dataStoreTransaction, this.user, this.requestId,
                    this.elideSettings, this.entityProjection, this.jsonApiDocument);
        }

        @Override
        public JsonApiRequestScopeBuilder route(Route route) {
            super.route(route);
            return this;
        }

        @Override
        public JsonApiRequestScopeBuilder dataStoreTransaction(DataStoreTransaction transaction) {
            super.dataStoreTransaction(transaction);
            return this;
        }

        @Override
        public JsonApiRequestScopeBuilder user(User user) {
            super.user(user);
            return this;
        }

        @Override
        public JsonApiRequestScopeBuilder requestId(UUID requestId) {
            super.requestId(requestId);
            return this;
        }

        @Override
        public JsonApiRequestScopeBuilder elideSettings(ElideSettings elideSettings) {
            super.elideSettings(elideSettings);
            return this;
        }

        @Override
        public JsonApiRequestScopeBuilder entityProjection(Function entityProjection) {
            super.entityProjection(entityProjection);
            return this;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy