1 /* 2 * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.management.internal; 26 27 import java.io.IOException; 28 import java.io.OutputStream; 29 import java.nio.file.Files; 30 import java.nio.file.Path; 31 import java.nio.file.StandardOpenOption; 32 import java.util.ArrayList; 33 import java.util.List; 34 import javax.management.ObjectName; 35 import com.sun.management.HotSpotDiagnosticMXBean; 36 import com.sun.management.HotSpotDiagnosticMXBean.ThreadDumpFormat; 37 import com.sun.management.VMOption; 38 import jdk.internal.vm.ThreadDumper; 39 import sun.management.Util; 40 41 /** 42 * Implementation of the diagnostic MBean for Hotspot VM. 43 */ 44 public class HotSpotDiagnostic implements HotSpotDiagnosticMXBean { 45 public HotSpotDiagnostic() { 46 } 47 48 @Override 49 public void dumpHeap(String outputFile, boolean live) throws IOException { 50 51 String propertyName = "jdk.management.heapdump.allowAnyFileSuffix"; 52 boolean allowAnyFileSuffix = Boolean.getBoolean(propertyName); 53 if (!allowAnyFileSuffix && !outputFile.endsWith(".hprof")) { 54 throw new IllegalArgumentException("heapdump file must have .hprof extension"); 55 } 56 57 dumpHeap0(outputFile, live); 58 } 59 60 private native void dumpHeap0(String outputFile, boolean live) throws IOException; 61 62 @Override 63 public List<VMOption> getDiagnosticOptions() { 64 List<Flag> allFlags = Flag.getAllFlags(); 65 List<VMOption> result = new ArrayList<>(); 66 for (Flag flag : allFlags) { 67 if (flag.isWriteable() && flag.isExternal()) { 68 result.add(flag.getVMOption()); 69 } 70 } 71 return result; 72 } 73 74 @Override 75 public VMOption getVMOption(String name) { 76 if (name == null) { 77 throw new NullPointerException("name cannot be null"); 78 } 79 80 Flag f = Flag.getFlag(name); 81 if (f == null) { 82 throw new IllegalArgumentException("VM option \"" + 83 name + "\" does not exist"); 84 } 85 return f.getVMOption(); 86 } 87 88 @Override 89 public void setVMOption(String name, String value) { 90 if (name == null) { 91 throw new NullPointerException("name cannot be null"); 92 } 93 if (value == null) { 94 throw new NullPointerException("value cannot be null"); 95 } 96 97 Flag flag = Flag.getFlag(name); 98 if (flag == null) { 99 throw new IllegalArgumentException("VM option \"" + 100 name + "\" does not exist"); 101 } 102 if (!flag.isWriteable()){ 103 throw new IllegalArgumentException("VM Option \"" + 104 name + "\" is not writeable"); 105 } 106 107 // Check the type of the value 108 Object v = flag.getValue(); 109 if (v instanceof Long) { 110 try { 111 long l = Long.parseLong(value); 112 Flag.setLongValue(name, l); 113 } catch (NumberFormatException e) { 114 throw new IllegalArgumentException("Invalid value:" + 115 " VM Option \"" + name + "\"" + 116 " expects numeric value", e); 117 } 118 } else if (v instanceof Double) { 119 try { 120 double d = Double.parseDouble(value); 121 Flag.setDoubleValue(name, d); 122 } catch (NumberFormatException e) { 123 throw new IllegalArgumentException("Invalid value:" + 124 " VM Option \"" + name + "\"" + 125 " expects numeric value", e); 126 } 127 } else if (v instanceof Boolean) { 128 if (!value.equalsIgnoreCase("true") && 129 !value.equalsIgnoreCase("false")) { 130 throw new IllegalArgumentException("Invalid value:" + 131 " VM Option \"" + name + "\"" + 132 " expects \"true\" or \"false\"."); 133 } 134 Flag.setBooleanValue(name, Boolean.parseBoolean(value)); 135 } else if (v instanceof String) { 136 Flag.setStringValue(name, value); 137 } else { 138 throw new IllegalArgumentException("VM Option \"" + 139 name + "\" is of an unsupported type: " + 140 v.getClass().getName()); 141 } 142 } 143 144 @Override 145 public ObjectName getObjectName() { 146 return Util.newObjectName("com.sun.management:type=HotSpotDiagnostic"); 147 } 148 149 @Override 150 public void dumpThreads(String outputFile, ThreadDumpFormat format) throws IOException { 151 Path file = Path.of(outputFile); 152 if (!file.isAbsolute()) 153 throw new IllegalArgumentException("'outputFile' not absolute path"); 154 155 try (OutputStream out = Files.newOutputStream(file, StandardOpenOption.CREATE_NEW)) { 156 dumpThreads(out, format); 157 } 158 } 159 160 private void dumpThreads(OutputStream out, ThreadDumpFormat format) throws IOException { 161 switch (format) { 162 case TEXT_PLAIN -> ThreadDumper.dumpThreads(out); 163 case JSON -> ThreadDumper.dumpThreadsToJson(out); 164 } 165 } 166 }