/* * Copyright 2015 Petr Bouda * * 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 org.joyrest.context.configurer; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; import org.joyrest.context.ApplicationContext; import org.joyrest.context.ApplicationContextImpl; import org.joyrest.context.autoconfigurar.AutoConfigurer; import org.joyrest.context.initializer.BeanFactory; import org.joyrest.context.initializer.InitContext; import org.joyrest.exception.InternalExceptionConfiguration; import org.joyrest.exception.configuration.ExceptionConfiguration; import org.joyrest.exception.configuration.TypedExceptionConfiguration; import org.joyrest.exception.handler.InternalExceptionHandler; import org.joyrest.exception.interceptor.ExceptionHandlerInterceptor; import org.joyrest.exception.type.RestException; import org.joyrest.interceptor.Interceptor; import org.joyrest.routing.ControllerConfiguration; import org.joyrest.routing.interceptor.PathParamProcessingInterceptor; import org.joyrest.transform.AbstractReaderWriter; import org.joyrest.transform.Reader; import org.joyrest.transform.Writer; import org.joyrest.transform.interceptor.SerializationInterceptor; import static org.joyrest.context.helper.CheckHelper.orderDuplicationCheck; import static org.joyrest.context.helper.ConfigurationHelper.createTransformers; import static org.joyrest.context.helper.ConfigurationHelper.sort; import static org.joyrest.context.helper.LoggingHelper.logExceptionHandler; import static org.joyrest.context.helper.LoggingHelper.logRoute; import static org.joyrest.context.helper.PopulateHelper.populateHandlerWriters; import static org.joyrest.context.helper.PopulateHelper.populateRouteReaders; import static org.joyrest.context.helper.PopulateHelper.populateRouteWriters; import static org.joyrest.utils.CollectionUtils.concat; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static java.util.Objects.nonNull; import static java.util.function.Function.identity; import static java.util.stream.Collectors.toMap; /** * Abstract class as a helper for initialization an {@link ApplicationContext}. * * @param <T> type of configurer class which is used to set up a configurer * @author pbouda * @see Configurer * @see NonDiConfigurer */ public abstract class AbstractConfigurer<T> implements Configurer<T> { protected static final List<Interceptor> COMMON_INTERCEPTORS; protected static final List<ExceptionConfiguration> COMMON_HANDLERS = singletonList( new InternalExceptionConfiguration()); static { COMMON_INTERCEPTORS = new ArrayList<>(); COMMON_INTERCEPTORS.add(new SerializationInterceptor()); COMMON_INTERCEPTORS.add(new PathParamProcessingInterceptor()); } /** * Method causes the initialization of the application context using the methods which returns a collection of beans such as * * @return initialized {@code application context} */ protected ApplicationContext initializeContext() { Function<Class<Object>, List<Object>> getBeans = this::getBeans; BeanFactory beanFactory = new BeanFactory(getBeans); InitContext context = new InitContext(); AutoConfigurer.configureInitializers() .forEach(initializer -> initializer.init(context, beanFactory)); List<AbstractReaderWriter> readersWriters = AutoConfigurer.configureReadersWriters(); ExceptionHandlerInterceptor exceptionHandlerInterceptor = new ExceptionHandlerInterceptor(); COMMON_INTERCEPTORS.add(exceptionHandlerInterceptor); Map<Boolean, List<Reader>> readers = createTransformers( concat(beanFactory.getAll(Reader.class), context.getReaders(), readersWriters)); Map<Boolean, List<Writer>> writers = createTransformers( concat(beanFactory.getAll(Writer.class), context.getWriters(), readersWriters)); List<Interceptor> interceptors = sort( concat(beanFactory.getAll(Interceptor.class), context.getInterceptors(), COMMON_INTERCEPTORS)); List<ExceptionConfiguration> handlers = concat(beanFactory.getAll(ExceptionConfiguration.class), context.getExceptionConfigurations(), COMMON_HANDLERS); List<ControllerConfiguration> controllers = concat(beanFactory.getAll(ControllerConfiguration.class), context.getControllerConfigurations()); orderDuplicationCheck(interceptors); Map<Class<? extends Exception>, InternalExceptionHandler> handlerMap = handlers.stream() .peek(ExceptionConfiguration::initialize) .flatMap(config -> config.getExceptionHandlers().stream()) .peek(handler -> { populateHandlerWriters(writers, handler, nonNull(handler.getResponseType())); logExceptionHandler(handler); }) .collect(toMap(InternalExceptionHandler::getExceptionClass, identity())); context.setExceptionHandlers(handlerMap); controllers.stream() .peek(ControllerConfiguration::initialize) .flatMap(config -> config.getRoutes().stream()) .peek(route -> { route.interceptor(interceptors.toArray(new Interceptor[interceptors.size()])); populateRouteReaders(readers, route); populateRouteWriters(writers, route); logRoute(route); }).forEach(context::addRoute); ApplicationContextImpl applicationContext = new ApplicationContextImpl(); applicationContext.setRoutes(context.getRoutes()); applicationContext.setExceptionHandlers(context.getExceptionHandlers()); exceptionHandlerInterceptor.setApplicationContext(applicationContext); return applicationContext; } }