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.rest.server.staticfile; 018 019import java.util.*; 020 021import org.apache.juneau.http.*; 022import org.apache.juneau.http.response.*; 023import org.apache.juneau.rest.server.*; 024import org.apache.juneau.rest.server.servlet.*; 025 026/** 027 * Standalone servlet companion of the {@link StaticFilesMixin} mixin. 028 * 029 * <p> 030 * Mounts as a <b>sibling top-level servlet</b> at {@code /static/*} and serves static files by 031 * delegating to the flavor-neutral {@link StaticFiles} worker bean resolved from the request context 032 * ({@link RestContext#getStaticFiles()}) — the same worker the {@link StaticFilesMixin mixin} 033 * and {@link StaticFilesResource child} flavors use, so the forms cannot drift. 034 * 035 * <p> 036 * Whereas the {@link StaticFilesMixin} mixin pins its op at {@code /static/*} for composition 037 * into a host at {@code /}, this companion declares the mount at the class level 038 * ({@link Rest#paths() @Rest(paths="/static/*")}) and pins the ops at {@code /*} — eliminating 039 * the path-doubling that a mixin-shaped op would produce when the servlet itself is mounted at 040 * {@code /static/*}. 041 * 042 * <h5 class='figure'>Microservice registration:</h5> 043 * 044 * <p class='bjava'> 045 * <ja>@Bean</ja> Servlet staticFiles() { 046 * <jk>return new</jk> StaticFilesServlet(); <jc>// auto-mounted at /static/* by JettyServerComponent</jc> 047 * } 048 * </p> 049 * 050 * <h5 class='section'>See Also:</h5><ul> 051 * <li class='jc'>{@link StaticFilesMixin} 052 * <li class='jc'>{@link StaticFilesResource} 053 * <li class='jc'>{@link StaticFiles} 054 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/StaticFiles">Static files</a> 055 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerComposition">REST Server — Mixins and Multi-Mount Paths</a> 056 * </ul> 057 * 058 * @serial exclude 059 * @since 10.0.0 060 */ 061// @formatter:off 062@Rest(paths="/static/*") 063public class StaticFilesServlet extends RestServlet { 064 065 private static final long serialVersionUID = 1L; 066 067 /** 068 * [GET /*] — serve a static file from the active {@link StaticFiles} worker bean. 069 * 070 * @param req The current REST request — supplies {@link RestContext#getStaticFiles()}. 071 * @param path The trailing remainder after the mount prefix. 072 * @param locale The request locale (used for localized resource lookups). 073 * @return The matching {@link HttpResource} (with content type + cache headers). 074 * @throws NotFound If no resource matches the requested path. 075 */ 076 @RestGet( 077 path="/*", 078 summary="Static files", 079 description="Static file retrieval.", 080 swagger=@OpSwagger(ignore=true) 081 ) 082 public HttpResource getStaticFile(RestRequest req, @Path("/*") String path, Locale locale) { 083 return req.getContext().getStaticFiles().resolve(path, locale).orElseThrow(NotFound::new); 084 } 085 086 /** 087 * [HEAD /*] — return GET headers for a static file without the body. 088 * 089 * @param req The current REST request — supplies {@link RestContext#getStaticFiles()}. 090 * @param path The trailing remainder after the mount prefix. 091 * @param locale The request locale (used for localized resource lookups). 092 * @return The matching {@link HttpResource} (with headers; body suppressed by the processor). 093 * @throws NotFound If no resource matches the requested path. 094 */ 095 @RestOp( 096 method="HEAD", 097 path="/*", 098 summary="Static files (HEAD)", 099 description="Static file metadata retrieval.", 100 swagger=@OpSwagger(ignore=true) 101 ) 102 public HttpResource headStaticFile(RestRequest req, @Path("/*") String path, Locale locale) { 103 return getStaticFile(req, path, locale); 104 } 105}