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.ops;
018
019import java.io.*;
020
021import org.apache.juneau.http.response.*;
022import org.apache.juneau.rest.server.*;
023import org.apache.juneau.rest.server.guard.*;
024import org.apache.juneau.rest.server.servlet.*;
025
026/**
027 * Child-resource flavor of the {@link AdminMixin} mixin.
028 *
029 * <p>
030 * Mounts as a <b>routed child</b> via {@link Rest#children() @Rest(children=AdminResource.class)} under
031 * a parent at the subtree {@code /admin} and serves the same operational endpoints ({@code /threads},
032 * {@code /heap}, {@code /cache/flush}, {@code /ratelimit}) as the mixin by delegating to a shared
033 * flavor-neutral {@link AdminProvider} worker bean &mdash; so the forms cannot drift.
034 *
035 * <p>
036 * Whereas the {@link AdminMixin} mixin pins its ops at {@code /admin/<endpoint>} for composition into a
037 * host at {@code /}, this child declares the subtree at the class level
038 * ({@link Rest#path() @Rest(path="/admin")}) and pins the ops at the bare endpoint names
039 * (e.g. {@code /threads}).
040 *
041 * <h5 class='section'>Default-deny security posture:</h5>
042 *
043 * <p>
044 * Like the mixin and servlet flavors, this child is annotated
045 * {@link Rest#guards() @Rest(guards=DenyAllGuard.class)}, so every admin path returns
046 * {@code 403 Forbidden} until the importer registers a {@link RestGuardList} factory.
047 *
048 * <h5 class='section'>See Also:</h5><ul>
049 *    <li class='jc'>{@link AdminMixin}
050 *    <li class='jc'>{@link AdminServlet}
051 *    <li class='jc'>{@link AdminProvider}
052 *    <li class='jc'>{@link DenyAllGuard}
053 *    <li class='jc'>{@link RestGuardList}
054 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestServerComposition">REST Server — Mixins and Multi-Mount Paths</a>
055 * </ul>
056 *
057 * @since 10.0.0
058 */
059// @formatter:off
060@Rest(
061   path="/admin",
062   guards=DenyAllGuard.class
063)
064public class AdminResource extends RestResource {
065
066   private final AdminProvider worker;
067
068   /** No-arg constructor &mdash; uses a default {@link AdminProvider} worker. */
069   public AdminResource() {
070      this(new AdminProvider());
071   }
072
073   /**
074    * Worker constructor.
075    *
076    * @param worker The shared flavor-neutral admin worker this child delegates to. Must not be
077    *    {@code null}.
078    */
079   protected AdminResource(AdminProvider worker) {
080      this.worker = worker;
081   }
082
083   /**
084    * [GET /threads] &mdash; emit a JSON list of currently-live threads.
085    *
086    * @param res The current REST response.
087    * @throws IOException If an I/O error occurs while writing the response.
088    */
089   @RestGet(
090      path="/threads",
091      summary="Thread dump",
092      description="JSON list of currently-live threads (filtered to exclude framework noise by default).",
093      swagger=@OpSwagger(ignore=true)
094   )
095   public void getThreads(RestResponse res) throws IOException {
096      worker.serveThreads(res);
097   }
098
099   /**
100    * [GET /heap] &mdash; emit JVM heap and non-heap memory statistics.
101    *
102    * @param res The current REST response.
103    * @throws IOException If an I/O error occurs while writing the response.
104    */
105   @RestGet(
106      path="/heap",
107      summary="Heap statistics",
108      description="JVM heap + non-heap memory statistics (Runtime + MemoryMXBean).",
109      swagger=@OpSwagger(ignore=true)
110   )
111   public void getHeap(RestResponse res) throws IOException {
112      worker.serveHeap(res);
113   }
114
115   /**
116    * [POST /cache/flush] &mdash; run all registered cache-flush hooks (or a subset).
117    *
118    * @param req The current REST request &mdash; {@code names} query parameter is read off it.
119    * @param res The current REST response.
120    * @throws IOException If an I/O error occurs while writing the response.
121    */
122   @RestPost(
123      path="/cache/flush",
124      summary="Cache flush",
125      description="Runs the registered cache-flush hooks (all by default; ?names=foo,bar for a subset).",
126      swagger=@OpSwagger(ignore=true)
127   )
128   public void postCacheFlush(RestRequest req, RestResponse res) throws IOException {
129      worker.serveCacheFlush(req, res);
130   }
131
132   /**
133    * [GET /ratelimit] &mdash; emit registered {@link RateLimitGuard} bean configuration.
134    *
135    * @param req The current REST request &mdash; supplies the bean store for guard lookup.
136    * @param res The current REST response.
137    * @throws IOException If an I/O error occurs while writing the response.
138    * @throws NotFound If no {@link RateLimitGuard} bean is registered on the importer's bean
139    *    store.
140    */
141   @RestGet(
142      path="/ratelimit",
143      summary="Rate-limit inspection",
144      description="JSON map of registered RateLimitGuard beans keyed by bean name.",
145      swagger=@OpSwagger(ignore=true)
146   )
147   public void getRateLimit(RestRequest req, RestResponse res) throws IOException {
148      worker.serveRateLimit(req, res);
149   }
150}