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.servlet; 018 019import org.apache.juneau.rest.server.*; 020import org.apache.juneau.rest.server.config.*; 021import org.apache.juneau.rest.server.ops.*; 022 023import jakarta.servlet.*; 024 025/** 026 * Specialized subclass of {@link BasicRestServlet} for showing "group" pages. 027 * 028 * <p> 029 * Meant as a base class for top-level REST resources in servlet containers. 030 * 031 * <p> 032 * Provides support for JSON, XML, HTML, URL-Encoding, UON, XML, OpenAPI, and MessagePack. See {@link BasicUniversalConfig} 033 * for details. 034 * 035 * <p> 036 * Adds the group-navigation endpoint ({@code GET /}) by composing {@link NavigationMixin} via 037 * {@link Rest#mixins() @Rest(mixins=...)} on top of the residual op-mixins inherited from 038 * {@link BasicRestServlet}. The navigation op lives on the {@code NavigationMixin} sub-context (backed by 039 * {@link RestMixin#getHostContext()}) but renders with the host's 040 * {@link org.apache.juneau.marshall.html.HtmlDocConfig @HtmlDocConfig} page decoration — mixin 041 * sub-contexts inherit the host's class-level {@code @HtmlDocConfig} (and other class-level config), so the 042 * navigation page matches the host's other endpoints. 043 * 044 * <p> 045 * Children are attached to this resource using the {@link Rest#children() @Rest(children)} annotation. 046 * 047 * <h5 class='section'>Dynamic children:</h5> 048 * 049 * <p> 050 * Additional child resources can be registered or unregistered at runtime via {@link #addChild(Class)} / 051 * {@link #removeChild(String)} (and overloads). This is particularly useful in test fixtures where a single 052 * group servlet is mounted once and individual tests plug in their own {@code @Rest} resources without restarting 053 * the servlet container. 054 * 055 * <h5 class='section'>See Also:</h5><ul> 056 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestAnnotatedClasses">@Rest-Annotated Class</a> 057 * </ul> 058 * 059 * @serial exclude 060 */ 061@Rest(mixins=NavigationMixin.class) 062public abstract class BasicRestServletGroup extends BasicRestServlet { 063 private static final long serialVersionUID = 1L; 064 065 /** 066 * Returns the {@link RestChildren} registry backing this group resource. 067 * 068 * <p> 069 * Use this for full access to the dynamic add/remove API, including the {@code replace} overloads and the 070 * unmodifiable {@link RestChildren#asMap() asMap()} snapshot. 071 * 072 * @return The {@link RestChildren} registry for this resource's {@link RestContext}. 073 */ 074 public RestChildren getChildResources() { 075 return getContext().getRestChildren(); 076 } 077 078 /** 079 * Dynamically registers a child REST resource by class. 080 * 081 * <p> 082 * Convenience pass-through to {@link RestChildren#addChild(Class)} on {@link #getChildResources()}. 083 * 084 * @param resourceClass The {@code @Rest}-annotated resource class. 085 * @return The newly-built child {@link RestContext}. 086 * @throws ServletException If construction or lifecycle initialization of the child fails. 087 */ 088 public RestContext addChild(Class<?> resourceClass) throws ServletException { 089 return getChildResources().addChild(resourceClass); 090 } 091 092 /** 093 * Dynamically registers a pre-instantiated child REST resource. 094 * 095 * <p> 096 * Convenience pass-through to {@link RestChildren#addChild(Object)} on {@link #getChildResources()}. 097 * 098 * @param resource The {@code @Rest}-annotated resource instance. 099 * @return The newly-built child {@link RestContext}. 100 * @throws ServletException If construction or lifecycle initialization of the child fails. 101 */ 102 public RestContext addChild(Object resource) throws ServletException { 103 return getChildResources().addChild(resource); 104 } 105 106 /** 107 * Dynamically registers a pre-instantiated child REST resource at an explicit path. 108 * 109 * <p> 110 * Convenience pass-through to {@link RestChildren#addChild(String, Object)} on {@link #getChildResources()}. 111 * 112 * @param path The path segment under this group at which to mount the child. 113 * @param resource The {@code @Rest}-annotated resource instance. 114 * @return The newly-built child {@link RestContext}. 115 * @throws ServletException If construction or lifecycle initialization of the child fails. 116 */ 117 public RestContext addChild(String path, Object resource) throws ServletException { 118 return getChildResources().addChild(path, resource); 119 } 120 121 /** 122 * Removes the child registered at the given composed path. 123 * 124 * <p> 125 * Convenience pass-through to {@link RestChildren#removeChild(String)} on {@link #getChildResources()}. 126 * 127 * @param path The composed path key (as returned by {@link RestContext#getPath()}). 128 * @return The removed and destroyed {@link RestContext}, or {@code null} if no child was registered there. 129 */ 130 public RestContext removeChild(String path) { 131 return getChildResources().removeChild(path); 132 } 133 134 /** 135 * Removes the first child whose resource class matches the given type. 136 * 137 * <p> 138 * Convenience pass-through to {@link RestChildren#removeChild(Class)} on {@link #getChildResources()}. 139 * 140 * @param resourceClass The resource class to match. 141 * @return The removed and destroyed {@link RestContext}, or {@code null} if no matching child was found. 142 */ 143 public RestContext removeChild(Class<?> resourceClass) { 144 return getChildResources().removeChild(resourceClass); 145 } 146}