/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.felix.webconsole.plugins.memoryusage.internal; import java.io.File; import java.io.PrintStream; import java.util.NoSuchElementException; import java.util.StringTokenizer; import org.apache.felix.shell.Command; class MemoryUsageCommand implements Command { private static final String HELP_CMD = "help"; private static final String POOLS_CMD = "pools"; private static final String DUMP_CMD = "dump"; private static final String OPT_DUMP_ALL = "-a"; private static final String LS_CMD = "ls"; private static final String RM_CMD = "rm"; private final MemoryUsageSupport support; MemoryUsageCommand(final MemoryUsageSupport support) { this.support = support; } public void execute(String commandLine, final PrintStream out, final PrintStream err) { final PrintWriterPrintHelper printHelper = new PrintWriterPrintHelper(out); // Parse the commandLine to get the mem command. final StringTokenizer st = new StringTokenizer(commandLine); // Ignore the invoking command. st.nextToken(); // Try to get the mem command, default is simple memory info dump. String command = null; try { command = st.nextToken(); } catch (Exception ex) { // Ignore. } // Perform the specified command. if (command == null) { mem(printHelper); } else if (command.equals(HELP_CMD)) { help(out, st); } else if (command.equals(POOLS_CMD)) { pools(printHelper); } else if (command.equals(DUMP_CMD)) { dump(out, st, err); } else if (command.equals(LS_CMD)) { ls(printHelper); } else if (command.equals(RM_CMD)) { rm(out, err, st); } else { err.println("Unknown command: " + command); } printHelper.flush(); } public String getName() { return "mem"; } public String getShortDescription() { return "Prints Java VM Memory Consumption or writes a heap dump"; } public String getUsage() { return "mem help"; } // ---------- internal private void mem(final MemoryUsageSupport.PrintHelper printHelper) { support.printOverallMemory(printHelper); } private void pools(final MemoryUsageSupport.PrintHelper printHelper) { support.printMemoryPools(printHelper); } private void help(final PrintStream out, final StringTokenizer word) { String command = HELP_CMD; if (word.hasMoreTokens()) { command = word.nextToken(); } if (command.equals(DUMP_CMD)) { out.printf("%s %s [ %s ]%n", getName(), DUMP_CMD, OPT_DUMP_ALL); out.println("This command requests a heap dump to be created. If the\n" + "-a option is not added, only live objects are dumped."); } else if (command.equals(LS_CMD)) { out.printf("%s %s%n", getName(), LS_CMD); out.println("This command lists all heap dumps created with the\n" + DUMP_CMD + " command."); } else if (command.equals(RM_CMD)) { out.printf("%s %s <dump>%n", getName(), RM_CMD); out.println("This command removes the indicated heap dump file.\n" + "Use the " + LS_CMD + " to list heap dumps which may be removed."); } else if (command.equals(POOLS_CMD)) { out.printf("%s %s%n", getName(), POOLS_CMD); out.println("This command shows information about all memory pools."); } else { out.printf("%s %s [ %s | %s | %s | %s ]%n", getName(), HELP_CMD, DUMP_CMD, LS_CMD, RM_CMD, POOLS_CMD); out.printf("%s %s [ %s ]%n", getName(), DUMP_CMD, OPT_DUMP_ALL); out.printf("%s %s%n", getName(), LS_CMD); out.printf("%s %s <dump>%n", getName(), RM_CMD); out.printf("%s %s%n", getName(), POOLS_CMD); out.println("Using the " + getName() + " command without any arguments prints a memory use overview."); } } private void dump(final PrintStream out, final StringTokenizer words, final PrintStream err) { String dumpTarget = null; boolean all = false; while (words.hasMoreTokens()) { String word = words.nextToken(); if (OPT_DUMP_ALL.equals(word)) { all = true; } else { dumpTarget = word; } } try { File dumpFile = support.dumpHeap(dumpTarget, !all); out.println("Heap dumped to " + dumpFile + " (" + dumpFile.length() + " bytes)"); } catch (NoSuchElementException e) { err.println("Failed dumping the heap, JVM does not provide known mechanism to create a Heap Dump"); } } private void ls(final MemoryUsageSupport.PrintHelper printHelper) { support.listDumpFiles(printHelper); } private void rm(final PrintStream out, final PrintStream err, final StringTokenizer words) { if (words.hasMoreTokens()) { do { final String name = words.nextToken(); if (support.rmDumpFile(name)) { out.println("rm: " + name + " removed"); out.flush(); } else { err.println("rm: " + name + ": No such dump file"); err.flush(); } } while (words.hasMoreTokens()); } } private static class PrintWriterPrintHelper implements MemoryUsageSupport.PrintHelper { private static final String INDENTS = " "; private final PrintStream pw; private String indent; PrintWriterPrintHelper(final PrintStream pw) { this.pw = pw; this.indent = ""; } public void title(String title, int level) { pw.printf("%s%s%n", getIndent(level - 1), title); indent = getIndent(level); } public void val(String value) { pw.printf("%s%s%n", indent, value); } public void keyVal(final String key, final Object value) { if (value == null) { val(key); } else { pw.printf("%s%s: %s%n", indent, key, value); } } void flush() { pw.flush(); } private static String getIndent(final int level) { if (level <= 0) { return ""; } final int indent = 2 * level; if (indent > INDENTS.length()) { return INDENTS; } return INDENTS.substring(0, indent); } } }