001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.petstore.springboot; 018 019import org.apache.juneau.petstore.console.*; 020import org.springframework.boot.autoconfigure.*; 021import org.springframework.boot.builder.*; 022import org.springframework.boot.web.servlet.*; 023import org.springframework.context.annotation.*; 024import org.springframework.core.*; 025import org.springframework.stereotype.*; 026 027import jakarta.servlet.*; 028import jakarta.servlet.DispatcherType; 029 030/** 031 * Petstore Spring Boot deployment entry point. 032 * 033 * <p> 034 * Boots a Spring Boot embedded servlet container, wires {@link RootResources} as a Spring bean, and mounts it at 035 * {@code /*} via {@link ServletRegistrationBean}. 036 * 037 * <p> 038 * Provides a {@code @Bean HelloMessageProvider} to demonstrate Spring {@code @Autowired} injection into the 039 * companion {@link HelloResource} child — preserving the deployment-glue Spring-injection demo. 040 * 041 * <h5 class='section'>See Also:</h5><ul> 042 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauPetstore">juneau-petstore</a> 043 * </ul> 044 */ 045@SuppressWarnings({ 046 "resource" // ApplicationContext is owned by Spring; not a leak. 047}) 048@SpringBootApplication 049@Controller 050public class App { 051 052 /** 053 * Entry point. 054 * 055 * @param args Command-line arguments forwarded to Spring Boot. 056 */ 057 public static void main(String[] args) { 058 new SpringApplicationBuilder(App.class).run(args); 059 } 060 061 /** 062 * Spring-injected message provider consumed by {@link HelloResource}. 063 * 064 * @return The hello-message provider bean. 065 */ 066 @Bean 067 public HelloMessageProvider helloMessageProvider() { 068 return new HelloMessageProvider("Hello from Spring-injected bean!"); 069 } 070 071 /** 072 * Returns {@link HelloResource} as a Spring bean with its dependency injected via constructor. 073 * 074 * @param helloMessageProvider The Spring-managed message provider bean. 075 * @return The hello-world REST resource. 076 */ 077 @Bean 078 public HelloResource helloResource(HelloMessageProvider helloMessageProvider) { 079 return new HelloResource(helloMessageProvider); 080 } 081 082 /** 083 * Returns the root router as a Spring bean so child resources resolve as Spring beans. 084 * 085 * @return The root router REST resource. 086 */ 087 @Bean 088 public RootResources rootResources() { 089 return new RootResources(); 090 } 091 092 /** 093 * The API's CSRF boundary: one instance, held here rather than exposed as a {@code Filter} bean so Spring Boot does 094 * not also auto-register it on {@code /*}. Shared by {@link #consoleBoundary()} and {@link #apiBoundary()}. 095 */ 096 private final PetstoreApiBoundary api = new PetstoreApiBoundary(); 097 098 /** 099 * Registers the console's CSRF boundary on {@code /console/*}. 100 * 101 * <p> 102 * The {@code /petstore} API is covered by {@link #apiBoundary()}; {@code /petstore-ui} is 103 * outside both. See {@link PetstoreConsoleBoundary}. The console boundary is built over the same 104 * {@link PetstoreApiBoundary} the API registration mounts, so the API token its pages carry is one the API filter 105 * accepts. 106 * 107 * <p> 108 * The filter runs on forwarded, async and error dispatches as well as on the original request, so a dispatch that 109 * lands on a console path is checked too. 110 * 111 * @return The filter registration. 112 */ 113 @Bean 114 public FilterRegistrationBean<PetstoreConsoleBoundary> consoleBoundary() { 115 var reg = new FilterRegistrationBean<>(new PetstoreConsoleBoundary(api)); 116 reg.addUrlPatterns(PetstoreConsoleBoundary.URL_PATTERN); 117 reg.setOrder(Ordered.HIGHEST_PRECEDENCE); 118 reg.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.FORWARD); 119 return reg; 120 } 121 122 /** 123 * Registers the API's CSRF boundary on {@code /petstore/*}. 124 * 125 * <p> 126 * It runs only on the original request: an internal forward or error dispatch to the API is not a new 127 * attacker-controlled request. The order keeps it just behind the console boundary; the two patterns never overlap. 128 * 129 * @return The filter registration. 130 */ 131 @Bean 132 public FilterRegistrationBean<PetstoreApiBoundary> apiBoundary() { 133 var reg = new FilterRegistrationBean<>(api); 134 reg.addUrlPatterns(PetstoreApiBoundary.URL_PATTERN); 135 reg.setOrder(Ordered.HIGHEST_PRECEDENCE + 10); 136 reg.setDispatcherTypes(DispatcherType.REQUEST); 137 return reg; 138 } 139 140 /** 141 * Mounts the root router servlet at {@code /*}. 142 * 143 * @param rootResources The Spring-managed root router. 144 * @return The servlet registration mapped to {@code /*}. 145 */ 146 @Bean 147 public ServletRegistrationBean<Servlet> rootServlet(RootResources rootResources) { 148 return new ServletRegistrationBean<>(rootResources, "/*"); 149 } 150}