Mercurial > hg > heapstats
view analyzer/plugin-api/src/main/java/jp/co/ntt/oss/heapstats/api/utils/HeapStatsUtils.java @ 279:898008f06beb
Bug 3766: HeapStats Analyzer plugin does not work
Reviewed-by: ykubota
https://github.com/HeapStats/heapstats/pull/152
author | Yasumasa Suenaga <yasuenag@gmail.com> |
---|---|
date | Mon, 11 Nov 2019 18:08:06 +0900 |
parents | dd85c1cbc8c8 |
children |
line wrap: on
line source
/* * Copyright (C) 2014-2019 Yasumasa Suenaga * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package jp.co.ntt.oss.heapstats.api.utils; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Properties; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; import javafx.scene.control.Alert; import javafx.scene.control.TextArea; import javafx.scene.paint.Color; import jp.co.ntt.oss.heapstats.api.WindowController; /** * Utility class for HeapStats FX Analyzer. * * @author Yasumasa Suenaga */ public class HeapStatsUtils { /* Rect size in Tooltip for chart legend. */ public static final double TOOLTIP_LEGEND_RECT_SIZE = 10.0d; /* Gap between each controls in Tooltip. */ public static final double TOOLTIP_GRIDPANE_GAP = 5.0d; /* Path of HeapStats home directory. */ private static Path currentPath = null; /* Properties for HeapStats analyzer. */ private static final Properties prop = new Properties(); /* Resource bundle for HeapStats Analyzer. */ private static ResourceBundle resource; /* Cached DateTimeFormatter */ private static DateTimeFormatter formatter; /* Main window controller */ private static WindowController controller; public static Path getHeapStatsHomeDirectory() { if (currentPath == null) { if (System.getProperty("heapstats.boot.mode").equals("jlink")) { currentPath = Path.of(System.getProperty("java.home")); } else { Pattern pat = Pattern.compile("heaptats-analzer[^" + System.getProperty("path.separator") + "]*\\.jar$"); currentPath = Stream.of(System.getProperty("java.class.path").split(System.getProperty("path.separator"))) .filter(s -> pat.matcher(s).matches()) .findFirst() .map(Path::of) .orElse(Path.of(".")); // If currentPath points to a file (e.g. heapstats-analyzer.jar), // currentPath set to parent path. if (currentPath.toFile().isFile()) { currentPath = currentPath.getParent(); } } } return currentPath; } /** * Load HeapStats property file. * * @author Yasumasa Suenaga * @throws IOException - I/O error to parse property file. * @throws HeapStatsConfigException - Invalid value. */ public static void load() throws IOException, HeapStatsConfigException { Path properties = Paths.get(getHeapStatsHomeDirectory().toString(), "heapstats.properties"); try (InputStream in = Files.newInputStream(properties, StandardOpenOption.READ)) { prop.load(in); } catch (NoSuchFileException e) { // use default values. } /* Load resource bundle */ resource = ResourceBundle.getBundle("HeapStatsResources"); /* Validate values in properties. */ /* Language */ String language = prop.getProperty("language"); if (language == null) { prop.setProperty("language", "en"); } else if (!language.equals("en") && !language.equals("ja")) { throw new HeapStatsConfigException(resource.getString("invalid.option") + " language=" + language); } /* Load resource bundle again */ resource = ResourceBundle.getBundle("HeapStatsResources", new Locale(prop.getProperty("language"))); /* RankLevel */ String rankLevelStr = prop.getProperty("ranklevel"); if (rankLevelStr == null) { prop.setProperty("ranklevel", "5"); } else { try { Integer.decode(rankLevelStr); } catch (NumberFormatException e) { throw new HeapStatsConfigException(resource.getString("invalid.option") + " ranklevel=" + rankLevelStr, e); } } /* ClassRename */ /* java.lang.Boolean#parseStinrg() does not throws Throwable. * If user sets invalid value, Boolean will treat "true" . * See javadoc of java.lang.Boolean . */ if (prop.getProperty("replace") == null) { prop.setProperty("replace", "false"); } /* Default directory for dialogs. */ if (prop.getProperty("defaultdir") == null) { prop.setProperty("defaultdir", getHeapStatsHomeDirectory().toString()); } else { /* check if defaultdir exists */ File defaultDir = new File(prop.getProperty("defaultdir")); if (!defaultDir.exists() || !defaultDir.isDirectory()) { prop.setProperty("defaultdir", getHeapStatsHomeDirectory().toString()); } } /* Log file list to parse. */ if (prop.getProperty("logfile") == null) { prop.setProperty("logfile", "redhat-release,cmdline,status,smaps,limits"); } /* Socket endpoint file to parse. */ if (prop.getProperty("socketend") == null) { prop.setProperty("socketend", "tcp,udp,tcp6,udp6"); } /* Socket owner file to parse. */ if (prop.getProperty("owner") == null) { prop.setProperty("owner", "sockowner"); } /* Background color to draw graphs. */ String bgColorStr = prop.getProperty("bgcolor"); if (bgColorStr == null) { prop.setProperty("bgcolor", "white"); } else { try { Color.web(bgColorStr); } catch (IllegalArgumentException e) { throw new HeapStatsConfigException(resource.getString("invalid.option") + " bgcolor=" + bgColorStr, e); } } /* Java Heap order */ String heapOrder = prop.getProperty("heaporder_bottom_young"); if (heapOrder == null) { prop.setProperty("heaporder", "true"); } /* DateTime format */ prop.putIfAbsent("datetime_format", "yyyy/MM/dd HH:mm:ss"); formatter = DateTimeFormatter.ofPattern(prop.getProperty("datetime_format")); /* Font size of RefTree */ String fontsize = prop.getProperty("reftree_fontsize"); if (fontsize == null) { prop.setProperty("reftree_fontsize", "11"); } else { try { Integer.decode(fontsize); } catch (NumberFormatException e) { throw new HeapStatsConfigException(resource.getString("invalid.option") + " reftree_fontsize=" + fontsize, e); } } /* Tick marker on X axis */ if (prop.getProperty("tickmarker") == null) { prop.setProperty("tickmarker", "false"); } /* TickUnit of X axis */ String xTickUnitStr = prop.getProperty("x_tickunit"); if (xTickUnitStr == null) { prop.setProperty("x_tickunit", "20"); } else { try { Double.parseDouble(xTickUnitStr); } catch (NumberFormatException e) { throw new HeapStatsConfigException(resource.getString("invalid.option") + " x_tickunit=" + xTickUnitStr, e); } } /* Add shutdown hook for saving current settings. */ Runnable savePropImpl = () -> { try (OutputStream out = Files.newOutputStream(properties, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)) { prop.store(out, null); } catch (IOException ex) { Logger.getLogger(HeapStatsUtils.class.getName()).log(Level.SEVERE, null, ex); } }; Runtime.getRuntime().addShutdownHook(new Thread(savePropImpl)); } /** * Get plugin list by config. * * @return Plugin list. */ public static List<String> getPlugins() { return Arrays.asList(prop.getProperty("plugins", "").split(";")) .stream() .map(s -> s.trim()) .filter(s -> s.length() > 0) .collect(Collectors.toList()); } /** * Get class name replacement. * * @return true if replace (Java-style). */ public static boolean getReplaceClassName() { return Boolean.parseBoolean(prop.getProperty("replace")); } /** * Get default directory. This value will be overriden when any file is * opened. * * @return Current default directory. */ public static String getDefaultDirectory() { return prop.getProperty("defaultdir"); } /** * Set default directory. * * @param currentDir New current directory. */ public static void setDefaultDirectory(String currentDir) { if (currentDir != null) { prop.setProperty("defaultdir", currentDir); } } /** * Get rank level. * * @return Rank level. */ public static int getRankLevel() { return Integer.parseInt(prop.getProperty("ranklevel")); } /** * Set rank level. * * @param rankLevel New rank level. */ public static void setRankLevel(int rankLevel) { prop.setProperty("ranklevel", Integer.toString(rankLevel)); } /** * Get background color of chart. * * @return Background color of chart. */ public static String getChartBgColor() { return prop.getProperty("bgcolor"); } /** * Get whether the bottom of java heap order is young or not. * * @return whether the bottom is young or not. */ public static boolean getHeapOrder() { return Boolean.parseBoolean(prop.getProperty("heaporder_bottom_young")); } /** * Set whethr the bottom of java heap order is young or not. * * @param heapOrder whether the bottom is young or not. */ public static void setHeapOrder(boolean heapOrder) { prop.setProperty("heaporder_bottom_young", Boolean.toString(heapOrder)); } /** * Get language. * * @return Language */ public static String getLanguage() { return prop.getProperty("language"); } /** * Get ResourceBundle. This value depends on getLanguage(). * * @return ResourceBundle. */ public static ResourceBundle getResourceBundle() { return ResourceBundle.getBundle("HeapStatsResources", new Locale(getLanguage())); } /** * Get DataTimeFormatter which is initialized by datetime_format value in heapstats.properties. * @return Instance of DateTimeFormatter. */ public static DateTimeFormatter getDateTimeFormatter(){ return formatter; } /** * Get font size of ReferenceTree tab. * @return fontSize */ public static int getFontSizeOfRefTree() { return Integer.parseInt(prop.getProperty("reftree_fontsize")); } /** * Get font size of ReferenceTree tab. * @param fontSize font size */ public static void setFontSizeOfRefTree( int fontSize ) { prop.setProperty("reftree_fontsize", Integer.toString(fontSize)); } /** * Get the switch to show tick marker on X axis. * * @return true if Analyzer should show tick marker. */ public static boolean getTickMarkerSwitch() { return Boolean.parseBoolean(prop.getProperty("tickmarker")); } /** * Get TickUnit on X axis. * * @return TickUnit of X axis. */ public static double getXTickUnit(){ return Double.parseDouble(prop.getProperty("x_tickunit")); } /** * Convert stack trace to String. * * @param e Throwable object to convert. * * @return String result of e.printStackTrace() */ public static String stackTraceToString(Throwable e) { String result = null; try (StringWriter strWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(strWriter)) { e.printStackTrace(printWriter); result = strWriter.toString(); } catch (IOException ex) { Logger.getLogger(HeapStatsUtils.class.getName()).log(Level.SEVERE, null, ex); } return result; } /** * Show alert dialog. * * @param e Throwable instance to show. */ public static void showExceptionDialog(Throwable e) { TextArea details = new TextArea(HeapStatsUtils.stackTraceToString(e)); details.setEditable(false); Alert dialog = new Alert(Alert.AlertType.ERROR); dialog.setTitle("Error"); dialog.setHeaderText(e.getLocalizedMessage()); dialog.getDialogPane().setExpandableContent(details); dialog.showAndWait(); } /** * Set an instance of main window controller. * * @param cont an instance of WindowController. */ public static void setWindowController(WindowController cont) { controller = cont; } /** * Get an instance of main window controller. */ public static WindowController getWindowController() { return controller; } }