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