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.management; 018 019import java.io.*; 020 021import org.apache.juneau.http.response.*; 022import org.apache.juneau.rest.server.*; 023import org.apache.juneau.rest.server.servlet.*; 024 025/** 026 * Child-resource flavor of the diagnostic dump endpoints ({@code /threaddump}, {@code /heapdump}). 027 * 028 * <p> 029 * Mounts as a routed child via {@link Rest#children() @Rest(children=DumpsResource.class)} and delegates to a 030 * shared {@link DumpsManager} worker — the same logic the {@link DumpsMixin mixin} flavor uses, so the 031 * two forms cannot drift. Extends {@link BasicRestResource} (mirrors {@code HealthResource}). 032 * 033 * <p> 034 * <b>Both dumps are deny-by-default</b> — they respond {@code 403 Forbidden} unless a 035 * {@link DumpsSettings} bean enabling them is registered. {@code /heapdump} additionally degrades to 036 * {@code 501 Not Implemented} on a JVM without HotSpot heap-dump support. 037 * 038 * <h5 class='section'>See Also:</h5><ul> 039 * <li class='jc'>{@link DumpsMixin} 040 * <li class='jc'>{@link DumpsManager} 041 * <li class='jc'>{@link DumpsSettings} 042 * </ul> 043 * 044 * @since 10.0.0 045 */ 046@Rest(path="/dumps") 047@SuppressWarnings({ 048 "resource" // getHeapDump() returns a self-deleting InputStream that the REST framework streams to the response and closes. 049}) 050public class DumpsResource extends BasicRestResource { 051 052 private final DumpsManager defaultManager = new DumpsManager(); 053 054 /** 055 * Returns the {@link DumpsManager} worker, resolved from the bean store when a consumer registers one, else a 056 * built-in default. Resolving through the bean store lets consumers (and tests) supply an alternate worker 057 * without subclassing. 058 * 059 * @param req The HTTP request (its context's bean store is searched). 060 * @return The resolved manager; never <jk>null</jk>. 061 */ 062 protected DumpsManager manager(RestRequest req) { 063 return req.getContext().getBeanStore().getBean(DumpsManager.class).orElse(defaultManager); 064 } 065 066 /** 067 * [GET /threaddump] - Full thread dump from the {@link java.lang.management.ThreadMXBean ThreadMXBean}. 068 * 069 * @param req The HTTP request. 070 * @return The thread dump text. 071 * @throws Forbidden If the thread-dump endpoint is not enabled. 072 */ 073 @RestGet( 074 path="/threaddump", 075 summary="Thread dump", 076 description="Renders a full thread dump from the JVM ThreadMXBean. Disabled by default; opt in via DumpsSettings." 077 ) 078 public String getThreadDump(RestRequest req) { 079 var manager = manager(req); 080 if (! manager.resolveSettings(req.getContext()).isThreadDumpEnabled()) 081 throw new Forbidden("The /threaddump endpoint is disabled. Register a DumpsSettings bean with threadDump enabled to use it."); 082 return manager.threadDump(); 083 } 084 085 /** 086 * [GET /heapdump] - HotSpot heap dump (hprof) stream. 087 * 088 * @param req The HTTP request. 089 * @param res The HTTP response. 090 * @return A self-deleting stream over the hprof file. 091 * @throws Forbidden If the heap-dump endpoint is not enabled. 092 * @throws NotImplemented If this JVM has no HotSpot heap-dump support. 093 * @throws IOException If the dump could not be produced. 094 */ 095 @RestGet( 096 path="/heapdump", 097 summary="Heap dump", 098 description="Produces a HotSpot heap dump (hprof). Disabled by default; opt in via DumpsSettings." 099 ) 100 public InputStream getHeapDump(RestRequest req, RestResponse res) throws IOException { 101 var manager = manager(req); 102 if (! manager.resolveSettings(req.getContext()).isHeapDumpEnabled()) 103 throw new Forbidden("The /heapdump endpoint is disabled. Register a DumpsSettings bean with heapDump enabled to use it."); 104 var stream = manager.heapDumpStream(true); 105 if (stream == null) // HTT: null only on a non-HotSpot JVM — not reproducible on HotSpot CI. 106 throw new NotImplemented("Heap dumps are not supported on this JVM (no HotSpotDiagnosticMXBean)."); 107 res.setHeader("Content-Type", "application/octet-stream"); 108 res.setHeader("Content-Disposition", "attachment; filename=\"heapdump.hprof\""); 109 return stream; 110 } 111}