001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest.springboot;
014
015import org.apache.juneau.rest.*;
016import org.apache.juneau.rest.springboot.annotation.*;
017import org.springframework.beans.BeansException;
018import org.springframework.beans.factory.config.*;
019import org.springframework.beans.factory.support.BeanDefinitionRegistry;
020import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
021import org.springframework.beans.factory.support.RootBeanDefinition;
022import org.springframework.boot.web.servlet.ServletRegistrationBean;
023import org.springframework.context.*;
024import org.springframework.core.type.*;
025
026import java.util.*;
027
028import javax.servlet.Servlet;
029
030/**
031 * Processes the {@link JuneauRestRoot} annotation on the Spring application class and <ja>@Bean</ja> methods.
032 */
033public class JuneauRestPostProcessor implements BeanDefinitionRegistryPostProcessor {
034
035   private final Class<?> appClass;
036   private final RestResourceResolver restResourceResolver;
037   private BeanDefinitionRegistry registry;
038
039   /**
040    * Constructor.
041    *
042    * @param ctx The spring application context.
043    * @param appClass The spring application class.
044    */
045   public JuneauRestPostProcessor(ConfigurableApplicationContext ctx, Class<?> appClass) {
046      this.appClass = appClass;
047      this.restResourceResolver = new SpringRestResourceResolver(ctx);
048   }
049
050   @Override /* BeanDefinitionRegistryPostProcessor */
051   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
052      this.registry = registry;
053   }
054
055   @Override /* BeanDefinitionRegistryPostProcessor */
056   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
057      try {
058         Map<String,RestServlet> m = new LinkedHashMap<>();
059
060         // @JuneauRestRoot on App class.
061         if (appClass != null) {
062            JuneauRestRoot a = appClass.getAnnotation(JuneauRestRoot.class);
063            if (a != null)
064               for (Class<? extends RestServlet> c : a.servlets())
065                  m.put(c.getName(), c.newInstance());
066         }
067
068         // @JuneauRestRoot on classes.
069         for (Map.Entry<String,Object> e : beanFactory.getBeansWithAnnotation(JuneauRestRoot.class).entrySet())
070            if (e.getValue() instanceof RestServlet)
071               m.put(e.getKey(), (RestServlet) e.getValue());
072
073         // @JuneauRestRoot on @Bean method.
074         for (String beanName : beanFactory.getBeanNamesForType(RestServlet.class)) {
075            BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
076            if (bd.getSource() instanceof AnnotatedTypeMetadata) {
077               AnnotatedTypeMetadata metadata = (AnnotatedTypeMetadata) bd.getSource();
078               if (metadata.isAnnotated(JuneauRestRoot.class.getName()))
079                  m.put(beanName, (RestServlet) beanFactory.getBean(beanName));
080            }
081         }
082
083         for (RestServlet rs : m.values()) {
084            rs.setRestResourceResolver(restResourceResolver);
085            ServletRegistrationBean<Servlet> reg = new ServletRegistrationBean<>(rs, '/' + rs.getPath());
086            registry.registerBeanDefinition(reg.getServletName(), new RootBeanDefinition(ServletRegistrationBean.class, () -> reg));
087         }
088
089      } catch (Exception e) {
090         throw new RuntimeException(e);
091      }
092   }
093}