springfox.documentation.spring.data.rest.EntityServicesProvider.java Source code

Java tutorial

Introduction

Here is the source code for springfox.documentation.spring.data.rest.EntityServicesProvider.java

Source

/*
 *
 *  Copyright 2016 the original author or authors.
 *
 *  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 springfox.documentation.spring.data.rest;

import com.fasterxml.classmate.TypeResolver;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.core.mapping.ResourceMappings;
import org.springframework.data.rest.core.mapping.ResourceType;
import org.springframework.data.rest.webmvc.BasePathAwareHandlerMapping;
import org.springframework.data.rest.webmvc.RepositoryRestHandlerMapping;
import org.springframework.data.rest.webmvc.RestMediaTypes;
import org.springframework.data.rest.webmvc.support.JpaHelper;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import springfox.documentation.RequestHandler;
import springfox.documentation.spi.service.RequestHandlerProvider;
import springfox.documentation.spring.web.WebMvcRequestHandler;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.google.common.base.Predicates.*;
import static com.google.common.collect.Lists.*;
import static org.springframework.http.MediaType.*;
import static springfox.documentation.spring.data.rest.EntityServices.*;

@Component
class EntityServicesProvider implements RequestHandlerProvider {
    private final ResourceMappings mappings;
    private final Repositories repositories;
    private final RepositoryRestHandlerMapping restMappings;
    private final BasePathAwareHandlerMapping basePathAwareMappings;
    private final TypeResolver typeResolver;

    @Autowired
    EntityServicesProvider(ResourceMappings mappings, JpaHelper jpaHelper,
            RepositoryRestConfiguration repositoryConfiguration, ApplicationContext applicationContext,
            Repositories repositories, TypeResolver typeResolver) {
        this.mappings = mappings;
        this.repositories = repositories;
        this.typeResolver = typeResolver;
        this.restMappings = new RepositoryRestHandlerMapping(mappings, repositoryConfiguration);
        restMappings.setJpaHelper(jpaHelper);
        restMappings.setApplicationContext(applicationContext);
        restMappings.afterPropertiesSet();

        basePathAwareMappings = new BasePathAwareHandlerMapping(repositoryConfiguration);
        basePathAwareMappings.setApplicationContext(applicationContext);
        basePathAwareMappings.afterPropertiesSet();
    }

    @Override
    public List<RequestHandler> requestHandlers() {
        ArrayList<RequestHandler> requestHandlers = newArrayList();
        FluentIterable<Map.Entry<RequestMappingInfo, HandlerMethod>> entries = FluentIterable.from(allEntries());
        for (Map.Entry<RequestMappingInfo, HandlerMethod> each : entries.filter(not(restDataServices()))) {
            requestHandlers.add(new WebMvcRequestHandler(each.getKey(), each.getValue()));
        }
        for (Map.Entry<RequestMappingInfo, HandlerMethod> each : entries.filter(repositories())) {
            requestHandlers.add(new WebMvcRequestHandler(each.getKey(), each.getValue()));
        }
        for (Map.Entry<RequestMappingInfo, HandlerMethod> each : entries.filter(entityServices())) {
            EntityRequestTemplate entityRequestTemplate = new EntityRequestTemplate(typeResolver, repositories,
                    mappings, each.getKey(), each.getValue());
            requestHandlers.addAll(entityRequestTemplate.operations());
        }
        List<RequestHandler> searchHandlers = newArrayList();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> each : entries.filter(entitySearchServices())) {
            EntitySearchRequestTemplate entityRequestHandlers = new EntitySearchRequestTemplate(typeResolver,
                    mappings, each.getKey(), each.getValue());
            searchHandlers.addAll(entityRequestHandlers.operations());
        }
        requestHandlers.addAll(maybeCombine(searchHandlers, compactHandlers()));

        List<RequestHandler> metadataHandlers = newArrayList();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> each : basePathAwareMappings.getHandlerMethods()
                .entrySet()) {
            if (entitySchemaService().apply(each) || alpsProfileServices().apply(each)) {
                metadataHandlers
                        .addAll(new EntitySchemaTemplate(typeResolver, mappings, each.getKey(), each.getValue())
                                .operations());
            } else {
                requestHandlers.add(new WebMvcRequestHandler(each.getKey(), each.getValue()));
            }
        }
        requestHandlers.addAll(maybeCombine(metadataHandlers, supportsAlps()));
        requestHandlers.addAll(FluentIterable.from(metadataHandlers).filter(optionMethods()).toList());
        return requestHandlers;
    }

    private Predicate<RequestHandler> optionMethods() {
        return new Predicate<RequestHandler>() {
            @Override
            public boolean apply(RequestHandler input) {
                return input.supportedMethods().contains(RequestMethod.OPTIONS);
            }
        };
    }

    private Collection<RequestHandler> maybeCombine(List<RequestHandler> metadataHandlers,
            Predicate<RequestHandler> selector) {
        List<RequestHandler> combined = newArrayList();
        Iterable<RequestHandler> selected = FluentIterable.from(metadataHandlers)
                .filter(and(selector, getHandler()));
        FluentIterable<RequestHandler> selectedCompliment = FluentIterable.from(metadataHandlers)
                .filter(and(not(selector), getHandler()));
        for (RequestHandler each : selected) {
            Optional<RequestHandler> found = selectedCompliment
                    .firstMatch(samePathMapping(each.getPatternsCondition()));
            combined.add(combine(each, found));
        }
        combined.addAll(FluentIterable.from(metadataHandlers).filter(EntitySearchRequestHandler.class)
                .filter(collectionHandlers()).toList());
        return combined;
    }

    private Predicate<EntitySearchRequestHandler> collectionHandlers() {
        return new Predicate<EntitySearchRequestHandler>() {
            @Override
            public boolean apply(EntitySearchRequestHandler input) {
                return input.resourceType() == ResourceType.COLLECTION;
            }
        };
    }

    private RequestHandler combine(RequestHandler source, Optional<RequestHandler> other) {
        if (other.isPresent()) {
            return other.get().combine(source);
        }
        return source;
    }

    private Predicate<RequestHandler> samePathMapping(final PatternsRequestCondition pathMappings) {
        return new Predicate<RequestHandler>() {
            @Override
            public boolean apply(RequestHandler input) {
                return input.getPatternsCondition().equals(pathMappings);
            }
        };
    }

    private Predicate<RequestHandler> compactHandlers() {
        return new Predicate<RequestHandler>() {
            @Override
            public boolean apply(RequestHandler input) {
                return input.key().getProducibleMediaTypes()
                        .contains(valueOf("application/x-spring-data-compact+json"));
            }
        };
    }

    private Predicate<RequestHandler> supportsAlps() {
        return new Predicate<RequestHandler>() {
            @Override
            public boolean apply(RequestHandler input) {
                return input.key().getSupportedMediaTypes().contains(RestMediaTypes.ALPS_JSON);
            }
        };
    }

    private Predicate<RequestHandler> getHandler() {
        return new Predicate<RequestHandler>() {
            @Override
            public boolean apply(RequestHandler input) {
                return input.key().getSupportedMethods().contains(RequestMethod.GET);
            }
        };
    }

    private Set<Map.Entry<RequestMappingInfo, HandlerMethod>> allEntries() {
        return restMappings.getHandlerMethods().entrySet();
    }
}