Mercurial > hg > release > thermostat-0.9
changeset 1076:0e9e22f2696a
Merge
author | Elliott Baron <ebaron@redhat.com> |
---|---|
date | Mon, 29 Apr 2013 11:54:04 -0400 |
parents | be3470750169 (current diff) dead5cab5a9a (diff) |
children | 00c6bf165dce |
files | |
diffstat | 15 files changed, 492 insertions(+), 167 deletions(-) [+] |
line wrap: on
line diff
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/timeline/TimelineRulerHeader.java Thu Apr 25 11:28:32 2013 -0400 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/timeline/TimelineRulerHeader.java Mon Apr 29 11:54:04 2013 -0400 @@ -56,11 +56,31 @@ @SuppressWarnings("serial") public abstract class TimelineRulerHeader extends GradientPanel { + /** Default height of this component. Subclasses may use different values */ + public static final int DEFAULT_HEIGHT = 25; + + /** + * Default increment is 20 pixels per units. + * Subclasses may use different values. + * + * @see #DEFAULT_INCREMENT_IN_MILLIS + */ + public static final int DEFAULT_INCREMENT_IN_PIXELS = 20; + + /** + * Default increments is 1 second (1000 ms) per pixel unit. + * Subclasses may use different values. + * + * @see #DEFAULT_INCREMENT_IN_PIXELS + */ + public static final long DEFAULT_INCREMENT_IN_MILLIS = 1_000; + private LongRange range; public TimelineRulerHeader(LongRange range) { super(Palette.LIGHT_GRAY.getColor(), Palette.WHITE.getColor()); + setFont(TimelineUtils.FONT); this.range = range; } @@ -71,7 +91,7 @@ @Override public int getHeight() { - return 25; + return DEFAULT_HEIGHT; } @Override @@ -87,6 +107,20 @@ return getPreferredSize(); } + /** + * Defines the distance, in pixels, between one tick mark and the other. + */ + public int getUnitIncrementInPixels() { + return DEFAULT_INCREMENT_IN_PIXELS; + } + + /** + * Defines how many milliseconds pass between two tick marks. + */ + public long getUnitIncrementInMillis() { + return DEFAULT_INCREMENT_IN_MILLIS; + } + protected abstract int getCurrentDisplayValue(); @Override @@ -99,11 +133,11 @@ int currentValue = getCurrentDisplayValue(); Rectangle bounds = g.getClipBounds(); - int totalInc = TimelineUtils.drawMarks(range, graphics, bounds, currentValue, - TimelineUtils.calculateWidth(range), - getHeight(), true); + + int unitIncrement = getUnitIncrementInPixels(); - drawTimelineStrings(graphics, currentValue, bounds, totalInc); + TimelineUtils.drawMarks(range, graphics, bounds, currentValue, false, unitIncrement); + drawTimelineStrings(graphics, currentValue, bounds, unitIncrement); graphics.setColor(Palette.THERMOSTAT_BLU.getColor()); graphics.drawLine(bounds.x, bounds.height - 1, bounds.width, bounds.height - 1); @@ -113,18 +147,19 @@ private void drawTimelineStrings(Graphics2D graphics, int currentValue, Rectangle bounds, int totalInc) { - Font font = TimelineUtils.FONT; - - graphics.setFont(font); - + Font font = graphics.getFont(); + DateFormat df = new SimpleDateFormat("HH:mm:ss"); Paint gradient = new GradientPaint(0, 0, Palette.WHITE.getColor(), 0, getHeight(), Palette.GRAY.getColor()); graphics.setColor(Palette.EARL_GRAY.getColor()); + + long incrementInMillis = getUnitIncrementInMillis(); - long round = range.getMin() % (TimelineUtils.STEP * 10); - int shift = (int) (round / TimelineUtils.STEP) * totalInc; + long round = range.getMin() % (10 * incrementInMillis); + + int shift = (int) (round / incrementInMillis) * totalInc; long currentTime = range.getMin() - round; int lowerBound = bounds.x - (4 * totalInc); @@ -148,7 +183,7 @@ graphics.setColor(Palette.THERMOSTAT_BLU.getColor()); graphics.drawString(value, i + 1, bounds.y + stringHeight + 5); } - currentTime += TimelineUtils.STEP; + currentTime += incrementInMillis; increment++; } }
--- a/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/timeline/TimelineUtils.java Thu Apr 25 11:28:32 2013 -0400 +++ b/client/swing/src/main/java/com/redhat/thermostat/client/swing/components/timeline/TimelineUtils.java Mon Apr 29 11:54:04 2013 -0400 @@ -42,46 +42,28 @@ import com.redhat.thermostat.client.ui.Palette; import com.redhat.thermostat.common.model.LongRange; -import com.redhat.thermostat.common.model.LongRangeNormalizer; public class TimelineUtils { - public static final int INC = 50; - public static final int STEP = 1000; public static final Font FONT = new Font("SansSerif", Font.PLAIN, 10); - - public static int calculateWidth(LongRange range) { - long span = range.getMax() - range.getMin(); - int width = (int) (span / TimelineUtils.INC); - return width; - } - - public static int drawMarks(LongRange range, Graphics2D graphics, Rectangle bounds, int currentValue, int width, int height) { - return drawMarks(range, graphics, bounds, currentValue, width, height, false); - } - - public static int drawMarks(LongRange range, Graphics2D graphics, Rectangle bounds, - int currentValue, int width, int height, boolean darkerTop) + + public static void drawMarks(LongRange range, Graphics2D graphics, Rectangle bounds, + int currentValue, boolean darkerTop, int increment) { - LongRangeNormalizer normalizer = new LongRangeNormalizer(range, 0, width); - normalizer.setValue(range.getMin() + TimelineUtils.STEP); - int totalInc = (int) normalizer.getValueNormalized(); - - int inc = currentValue % totalInc; + int inc = currentValue % increment; int x = (bounds.x - inc); graphics.setColor(Palette.GRAY.getColor()); int upperBound = (bounds.x + bounds.width); - for (int i = x; i < upperBound; i += totalInc) { - graphics.drawLine(i, 0, i, height); + for (int i = x; i < upperBound; i += increment) { + graphics.drawLine(i, 0, i, bounds.height); if (darkerTop) { graphics.setColor(Palette.DARK_GRAY.getColor()); graphics.drawLine(i, 0, i, 5); graphics.setColor(Palette.GRAY.getColor()); } } - - return totalInc; } + }
--- a/distribution/docs/plugin.xsd Thu Apr 25 11:28:32 2013 -0400 +++ b/distribution/docs/plugin.xsd Mon Apr 29 11:54:04 2013 -0400 @@ -9,6 +9,7 @@ <xs:element name="name" type="xs:string"/> <xs:element name="bundle" type="xs:string"/> <xs:element name="dependency" type="xs:string"/> +<xs:element name="usage" type="xs:string"/> <xs:element name="description" type="xs:string"/> <xs:element name="short" type="xs:string"/> <xs:element name="long" type="xs:string"/> @@ -62,7 +63,9 @@ <xs:complexType> <xs:sequence> <xs:element ref="name"/> + <xs:element ref="usage" minOccurs="0" maxOccurs="1"/> <xs:element ref="description"/> + <xs:element ref="arguments" minOccurs="0" maxOccurs="1"/> <xs:element ref="options"/> <xs:element ref="bundles"/> <xs:element ref="dependencies"/> @@ -71,6 +74,14 @@ </xs:element> +<xs:element name="arguments"> + <xs:complexType> + <xs:sequence> + <xs:element ref="argument" minOccurs="0" maxOccurs="1"/> + </xs:sequence> + </xs:complexType> +</xs:element> + <xs:element name="options"> <xs:complexType> <xs:sequence>
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/StorageConnectionTest.java Thu Apr 25 11:28:32 2013 -0400 +++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/StorageConnectionTest.java Mon Apr 29 11:54:04 2013 -0400 @@ -40,6 +40,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import expectj.ExpectJException; @@ -66,6 +67,7 @@ assertNoExceptions(storage.getCurrentStandardOutContents(), storage.getCurrentStandardErrContents()); } + @Ignore //FIXME when keyring/preferences improvements have been made, un-Ignore @Test public void testConnect() throws ExpectJException, TimeoutException, IOException { Spawn shell = spawnThermostat(true, "shell"); @@ -95,6 +97,7 @@ assertNoExceptions(shell.getCurrentStandardOutContents(), shell.getCurrentStandardErrContents()); } + @Ignore //FIXME when keyring/preferences improvements have been made, un-Ignore @Test public void testConnectAndDisconnectInShell() throws IOException, TimeoutException, ExpectJException { Spawn shell = spawnThermostat(true, "shell");
--- a/integration-tests/src/test/java/com/redhat/thermostat/itest/VmCommandsTest.java Thu Apr 25 11:28:32 2013 -0400 +++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/VmCommandsTest.java Mon Apr 29 11:54:04 2013 -0400 @@ -45,6 +45,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import expectj.Spawn; @@ -69,6 +70,7 @@ stopStorage.waitFor(); } + @Ignore //FIXME when keyring/preferences improvements have been made, un-Ignore @Test public void testListVms() throws Exception { Spawn vmList = commandAgainstMongo("list-vms"); @@ -99,6 +101,7 @@ assertNoExceptions(vmInfo.getCurrentStandardOutContents(), vmInfo.getCurrentStandardErrContents()); } + @Ignore //FIXME when keyring/preferences improvements have been made, un-Ignore @Test public void testHeapCommands() throws Exception { String[] commands = new String[] {
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSource.java Thu Apr 25 11:28:32 2013 -0400 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSource.java Mon Apr 29 11:54:04 2013 -0400 @@ -69,14 +69,18 @@ private static final Logger logger = LoggingUtils.getLogger(PluginCommandInfoSource.class); + private final UsageStringBuilder usageBuilder; + private Map<String, BasicCommandInfo> allNewCommands = new HashMap<>(); private Map<String, List<String>> additionalBundlesForExistingCommands = new HashMap<>(); public PluginCommandInfoSource(String internalJarRoot, String pluginRootDir) { - this(new File(internalJarRoot), new File(pluginRootDir), new PluginConfigurationParser()); + this(new File(internalJarRoot), new File(pluginRootDir), new PluginConfigurationParser(), new UsageStringBuilder()); } - PluginCommandInfoSource(File internalJarRoot, File pluginRootDir, PluginConfigurationParser parser) { + PluginCommandInfoSource(File internalJarRoot, File pluginRootDir, PluginConfigurationParser parser, UsageStringBuilder usageBuilder) { + this.usageBuilder = usageBuilder; + File[] pluginDirs = pluginRootDir.listFiles(); if (pluginDirs == null) { logger.log(Level.SEVERE, "plugin root dir " + pluginRootDir + " does not exist"); @@ -132,9 +136,13 @@ addIfValidPath(bundlePaths, coreJarRoot, command.getDepenedencyBundles()); + String usage = command.getUsage(); + if (usage == null) { + usage = usageBuilder.getUsage(commandName, command.getOptions(), command.getPositionalArguments().toArray(new String[0])); + } BasicCommandInfo info = new BasicCommandInfo(commandName, command.getDescription(), - command.getUsage(), + usage, command.getOptions(), bundlePaths);
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfiguration.java Thu Apr 25 11:28:32 2013 -0400 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfiguration.java Mon Apr 29 11:54:04 2013 -0400 @@ -87,16 +87,20 @@ public static class NewCommand { private final String commandName; + private final String usage; private final String description; - private String usage; + private final List<String> positionalArguments; private final Options options; private final List<String> additionalResources; private final List<String> coreDeps; - public NewCommand(String name, String description, - Options options, List<String> additionalResources, List<String> coreDeps) { + public NewCommand(String name, String usage, String description, + List<String> positionalArguments, Options options, + List<String> additionalResources, List<String> coreDeps) { this.commandName = name; + this.usage = usage; this.description = description; + this.positionalArguments = positionalArguments; this.options = options; this.additionalResources = additionalResources; this.coreDeps = coreDeps; @@ -106,14 +110,25 @@ return commandName; } + /** + * The usage string may be null if no usage string was explicitly + * provided. In that case, usage should be "computed" using options and + * arguments + */ + public String getUsage() { + return usage; + } + public String getDescription() { return description; } - public String getUsage() { - return usage; + /** Returns a list of strings indicating positional arguments */ + public List<String> getPositionalArguments() { + return positionalArguments; } + /** Returns options (both optional and required) */ public Options getOptions() { return options; }
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java Thu Apr 25 11:28:32 2013 -0400 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParser.java Mon Apr 29 11:54:04 2013 -0400 @@ -285,7 +285,7 @@ } if (bundles.isEmpty()) { - logger.warning("plugin " + pluginName + " extends the command " + name + " but supplies no bundles"); + logger.warning("plugin " + pluginName + " extends the command " + name + " but supplies no bundles"); } if (name == null) { @@ -297,7 +297,9 @@ private NewCommand parseNewCommand(String pluginName, Node commandNode) { String name = null; + String usage = null; String description = null; + List<String> arguments = new ArrayList<>(); Options options = new Options(); List<String> bundles = new ArrayList<>(); List<String> dependencies = new ArrayList<>(); @@ -307,8 +309,12 @@ Node node = nodes.item(i); if (node.getNodeName().equals("name")) { name = node.getTextContent().trim(); + } else if (node.getNodeName().equals("usage")) { + usage = node.getTextContent().trim(); } else if (node.getNodeName().equals("description")) { description = node.getTextContent().trim(); + } else if (node.getNodeName().equals("arguments")) { + arguments = parseArguments(pluginName, name, node); } else if (node.getNodeName().equals("options")) { options = parseOptions(node); } else if (node.getNodeName().equals("bundles")) { @@ -330,44 +336,39 @@ "name='" + name + "', description='" + description + "', options='" + options + "'"); return null; } else { - return new NewCommand(name, description, options, bundles, dependencies); + return new NewCommand(name, usage, description, arguments, options, bundles, dependencies); } } private Collection<String> parseBundles(String pluginName, String commandName, Node bundlesNode) { - List<String> bundles = new ArrayList<>(); - NodeList nodes = bundlesNode.getChildNodes(); + return parseNodeAsList(pluginName, commandName, bundlesNode, "bundle"); + } + + private Collection<String> parseDependencies(String pluginName, String commandName, Node dependenciesNode) { + return parseNodeAsList(pluginName, commandName, dependenciesNode, "dependency"); + } + + private List<String> parseArguments(String pluginName, String commandName, Node argumentsNode) { + return parseNodeAsList(pluginName, commandName, argumentsNode, "argument"); + } + + private List<String> parseNodeAsList(String pluginName, String commandName, Node parentNode, String childElementName) { + List<String> result = new ArrayList<>(); + NodeList nodes = parentNode.getChildNodes(); for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item(i); - if (node.getNodeName().equals("bundle")) { - String bundleName = node.getTextContent().trim(); - bundles.add(bundleName); + if (node.getNodeName().equals(childElementName)) { + String data = node.getTextContent().trim(); + result.add(data); } } - if (bundles.isEmpty()) { - logger.warning("plugin " + pluginName + " has an empty bundles element for command " + commandName); + if (result.isEmpty()) { + logger.warning("plugin " + pluginName + " has an empty " + parentNode.getNodeName() + + " element for command " + commandName); } - return bundles; - } - - private Collection<String> parseDependencies(String pluginName, String commandName, Node dependenciesNode) { - List<String> dependencies = new ArrayList<>(); - NodeList nodes = dependenciesNode.getChildNodes(); - for (int i = 0; i < nodes.getLength(); i++) { - Node node = nodes.item(i); - if (node.getNodeName().equals("dependency")) { - String bundleName = node.getTextContent().trim(); - dependencies.add(bundleName); - } - } - - if (dependencies.isEmpty()) { - logger.warning("plugin " + pluginName + " has an empty dependencies element for command " + commandName); - } - - return dependencies; + return result; } private Options parseOptions(Node optionsNode) { @@ -479,8 +480,10 @@ } } - Option opt = new Option(shortName, longName, Boolean.parseBoolean(argument), description); - opt.setArgName(longName != null? longName : shortName); + Option opt = new Option(shortName, longName, (argument != null), description); + if (argument != null) { + opt.setArgName(argument); + } opt.setRequired(required); return opt; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/UsageStringBuilder.java Mon Apr 29 11:54:04 2013 -0400 @@ -0,0 +1,106 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.launcher.internal; + +import java.util.Collection; + +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; + +public class UsageStringBuilder { + + /** + * Generates a 'usage' string based on the name (of a program) and the + * options that program will accept on the command line. + * + * @param name the program name + * @param options the options accepted by this program + * @return a String representing the usage. + */ + public String getUsage(String name, Options options, String... positionalArguments) { + StringBuilder result = new StringBuilder(); + result.append(name); + // commons-cli has no support for generics, so suppress this warning. + @SuppressWarnings("unchecked") + Collection<Option> opts = options.getOptions(); + // iterate twice to handle/print required options first, followed by optional ones + for (Option option : opts) { + appendOption(result, option, true); + } + for (Option option : opts) { + appendOption(result, option, false); + } + // print positional arguments last + if (positionalArguments != null) { + for (String positionalArg : positionalArguments) { + result.append(" ").append(positionalArg); + } + } + + return result.toString(); + } + + private void appendOption(StringBuilder result, Option option, boolean requiredOptionsOnly) { + if (option.isRequired() != requiredOptionsOnly) { + return; + } + + result.append(" "); + + if (!option.isRequired()) { + result.append("["); + } + + // prefer to display long form if available + if (option.hasLongOpt()) { + result.append("--").append(option.getLongOpt()); + } else { + result.append("-").append(option.getOpt()); + } + + if (option.hasArg()) { + result.append(" ").append("<").append(option.getArgName()).append(">"); + } else if (option.hasOptionalArg()) { + result.append("[").append(" ").append("<").append(option.getArgName()).append(">").append("]"); + } + + if (!option.isRequired()) { + result.append("]"); + } + } + +}
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSourceTest.java Thu Apr 25 11:28:32 2013 -0400 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginCommandInfoSourceTest.java Mon Apr 29 11:54:04 2013 -0400 @@ -71,12 +71,14 @@ private Path pluginRootDir; private PluginConfigurationParser parser; private PluginConfiguration parserResult; + private UsageStringBuilder usageBuilder; @Before public void setUp() throws IOException { parser = mock(PluginConfigurationParser.class); parserResult = mock(PluginConfiguration.class); when(parser.parse(isA(File.class))).thenReturn(parserResult); + usageBuilder = mock(UsageStringBuilder.class); testRoot = Files.createTempDirectory("thermostat"); pluginRootDir = testRoot.resolve("plugins"); @@ -115,7 +117,7 @@ Files.createDirectory(pluginDir); } - new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser); + new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser, usageBuilder); ArgumentCaptor<File> configFilesCaptor = ArgumentCaptor.forClass(File.class); verify(parser, times(pluginDirs.length)).parse(configFilesCaptor.capture()); @@ -131,12 +133,12 @@ public void verifyMissingConfigurationFileIsHandledCorrectly() throws FileNotFoundException { when(parser.parse(isA(File.class))).thenThrow(new FileNotFoundException("test")); - new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser); + new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser, usageBuilder); } @Test(expected = CommandInfoNotFoundException.class) public void verifyMissingCommandInfo() { - PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser); + PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser, usageBuilder); source.getCommandInfo("TEST"); } @@ -161,7 +163,7 @@ when(parserResult.getExtendedCommands()).thenReturn(Arrays.asList(extensions)); - PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser); + PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser, usageBuilder); CommandInfo info = source.getCommandInfo("command-name"); assertEquals("command-name", info.getName()); @@ -193,14 +195,14 @@ NewCommand cmd = mock(NewCommand.class); when(cmd.getCommandName()).thenReturn(NAME); when(cmd.getDescription()).thenReturn(DESCRIPTION); - when(cmd.getUsage()).thenReturn(USAGE); + when(usageBuilder.getUsage(NAME, OPTIONS)).thenReturn(USAGE); when(cmd.getOptions()).thenReturn(OPTIONS); when(cmd.getPluginBundles()).thenReturn(Arrays.asList(PLUGIN_BUNDLE)); when(cmd.getDepenedencyBundles()).thenReturn(Arrays.asList(DEPENDENCY_BUNDLE)); when(parserResult.getNewCommands()).thenReturn(Arrays.asList(cmd)); - PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser); + PluginCommandInfoSource source = new PluginCommandInfoSource(jarRootDir.toFile(), pluginRootDir.toFile(), parser, usageBuilder); CommandInfo result = source.getCommandInfo(NAME);
--- a/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParserTest.java Thu Apr 25 11:28:32 2013 -0400 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/PluginConfigurationParserTest.java Mon Apr 29 11:54:04 2013 -0400 @@ -187,6 +187,41 @@ } @Test + public void testArgumentParsing() throws UnsupportedEncodingException { + String config = "<?xml version=\"1.0\"?>\n" + + "<plugin>\n" + + " <commands>\n" + + " <command type='provides'>\n" + + " <name>test</name>\n" + + " <description>just a test</description>\n" + + " <arguments>\n" + + " <argument>file</argument>\n" + + " </arguments>\n" + + " </command>\n" + + " </commands>\n" + + "</plugin>"; + + PluginConfiguration result = new PluginConfigurationParser() + .parse("test", new ByteArrayInputStream(config.getBytes("UTF-8"))); + + assertEquals(0, result.getExtendedCommands().size()); + + List<NewCommand> newCommands = result.getNewCommands(); + assertEquals(1, newCommands.size()); + + NewCommand command = newCommands.get(0); + assertEquals("test", command.getCommandName()); + assertEquals("just a test", command.getDescription()); + assertEquals(null, command.getUsage()); + Options opts = command.getOptions(); + assertTrue(opts.getOptions().isEmpty()); + + List<String> args = command.getPositionalArguments(); + assertEquals(1, args.size()); + assertEquals("file", args.get(0)); + } + + @Test public void testOptionParsing() throws UnsupportedEncodingException { String config = "<?xml version=\"1.0\"?>\n" + "<plugin>\n" + @@ -200,14 +235,12 @@ " <option>\n" + " <long>exclusive-a</long>\n" + " <short>a</short>\n" + - " <argument>false</argument>\n" + " <required>false</required>\n" + " <description>exclusive option a</description>\n" + " </option>\n" + " <option>\n" + " <long>exclusive-b</long>\n" + " <short>b</short>\n" + - " <argument>false</argument>\n" + " <required>false</required>\n" + " <description>exclusive option b</description>\n" + " </option>\n" + @@ -215,7 +248,7 @@ " <option>\n" + " <long>long</long>\n" + " <short>l</short>\n" + - " <argument>true</argument>\n" + + " <argument>name</argument>\n" + " <required>true</required>\n" + " <description>some required and long option</description>\n" + " </option>\n" +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/launcher/src/test/java/com/redhat/thermostat/launcher/internal/UsageStringBuilderTest.java Mon Apr 29 11:54:04 2013 -0400 @@ -0,0 +1,149 @@ +/* + * Copyright 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat 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, or (at your + * option) any later version. + * + * Thermostat 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 Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.launcher.internal; + +import static org.junit.Assert.assertEquals; + +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.junit.Before; +import org.junit.Test; + +public class UsageStringBuilderTest { + + private UsageStringBuilder builder; + + @Before + public void setUp() { + builder = new UsageStringBuilder(); + } + + @Test + public void verifyUsageWithNoOptions() { + Options options = new Options(); + String usage = builder.getUsage("test", options); + assertEquals("test", usage); + } + + @Test + public void verifyUsageWithSingleShortOption() { + Option a = new Option("a", "something"); + a.setRequired(false); + Options options = new Options(); + options.addOption(a); + + String usage = builder.getUsage("test", options); + assertEquals("test [-a]", usage); + } + + @Test + public void verifyUsageWithShortAndLongOptions() { + Options options = new Options(); + + Option a = new Option("a", "something"); + options.addOption(a); + + Option b = new Option("b", "bee", false, "another thing"); + options.addOption(b); + + String usage = builder.getUsage("test", options); + assertEquals("test [--bee] [-a]", usage); + } + + @Test + public void verifyOptionWithArgument() { + Options options = new Options(); + + Option a = new Option("a", true, "something"); + a.setArgName("aaah"); + options.addOption(a); + + String usage = builder.getUsage("test", options); + assertEquals("test [-a <aaah>]", usage); + } + + @Test + public void verifyRequiredSingleShortOption() { + Option a = new Option("a", "something"); + a.setRequired(true); + Options options = new Options(); + options.addOption(a); + + String usage = builder.getUsage("test", options); + assertEquals("test -a", usage); + } + + @Test + public void verifyRequiredOptionsBeforeOptionalOnes() { + Options options = new Options(); + + Option a = new Option("a", "something"); + a.setRequired(true); + options.addOption(a); + + Option b = new Option("b", "something"); + b.setRequired(false); + options.addOption(b); + + Option c = new Option("c", "something"); + c.setRequired(false); + options.addOption(c); + + String usage = builder.getUsage("test", options); + assertEquals("test -a [-b] [-c]", usage); + } + + @Test + public void verifyPositionArgumentsAreIncluded() { + Options options = new Options(); + + String usage = builder.getUsage("test", options, "agent-id", "vm-id"); + assertEquals("test agent-id vm-id", usage); + } + + @Test + public void verifyPositionArgumentsAreDisplayedLast() { + Options options = new Options(); + + Option a = new Option("a", "something"); + a.setRequired(true); + options.addOption(a); + + String usage = builder.getUsage("test", options, "agent-id", "vm-id"); + assertEquals("test -a agent-id vm-id", usage); + } +}
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTimelineView.java Thu Apr 25 11:28:32 2013 -0400 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/SwingThreadTimelineView.java Mon Apr 29 11:54:04 2013 -0400 @@ -52,9 +52,11 @@ import com.redhat.thermostat.client.swing.ComponentVisibleListener; import com.redhat.thermostat.client.swing.SwingComponent; + import com.redhat.thermostat.client.swing.components.timeline.TimelineRulerHeader; -import com.redhat.thermostat.client.swing.components.timeline.TimelineUtils; + import com.redhat.thermostat.common.model.LongRange; + import com.redhat.thermostat.thread.client.common.Timeline; import com.redhat.thermostat.thread.client.common.view.ThreadTimelineView; @@ -113,7 +115,8 @@ scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); long now = System.currentTimeMillis(); - header = new ThreadTimelineHeader(new LongRange(now, now + TimelineUtils.STEP), scrollPane); + header = new ThreadTimelineHeader(new LongRange(now, now + TimelineRulerHeader.DEFAULT_INCREMENT_IN_MILLIS), + scrollPane); scrollPane.setColumnHeaderView(header); ScrollChangeListener listener = new ScrollChangeListener(); @@ -134,7 +137,7 @@ int extent = scrollBar.getVisibleAmount(); int min = scrollBar.getMinimum(); - int max = component.getWidth() + (2 * TimelineUtils.INC); + int max = component.getWidth() + (int) (2 * header.getUnitIncrementInMillis()); scrollBar.setValues(max - extent, extent, min, max); } @@ -148,10 +151,15 @@ SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - range.setMax(range.getMax() + (2 * TimelineUtils.STEP)); + range.setMax(range.getMax() + (int) (2 * header.getUnitIncrementInMillis())); chartModel.removeAllElements(); for (Timeline timeline : timelines) { - chartModel.addElement(new TimelineComponent(range, timeline, scrollPane)); + + TimelineComponent timelineComp = new TimelineComponent(range, timeline, scrollPane); + timelineComp.setUnitIncrementInMillis(header.getUnitIncrementInMillis()); + timelineComp.setUnitIncrementInPixels(header.getUnitIncrementInPixels()); + + chartModel.addElement(timelineComp); } header.getRange().setMin(range.getMin()); header.getRange().setMax(range.getMax());
--- a/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/TimelineComponent.java Thu Apr 25 11:28:32 2013 -0400 +++ b/thread/client-swing/src/main/java/com/redhat/thermostat/thread/client/swing/impl/timeline/TimelineComponent.java Mon Apr 29 11:54:04 2013 -0400 @@ -56,6 +56,7 @@ import com.redhat.thermostat.client.swing.GraphicsUtils; import com.redhat.thermostat.client.swing.components.GradientPanel; + import com.redhat.thermostat.client.swing.components.timeline.TimelineUtils; import com.redhat.thermostat.client.ui.Palette; @@ -74,13 +75,29 @@ private Timeline timeline; private JScrollPane scrollPane; private LongRange range; - public TimelineComponent(LongRange range, Timeline timeline, JScrollPane scrollPane) { + + private long millsUnitIncrement; + private int pixelUnitIncrement; + + public TimelineComponent(LongRange range, Timeline timeline, JScrollPane scrollPane) + { super(Palette.LIGHT_GRAY.getColor(), Palette.WHITE.getColor()); this.range = range; this.scrollPane = scrollPane; this.timeline = timeline; + + millsUnitIncrement = 1_000; + pixelUnitIncrement = 20; } + public void setUnitIncrementInPixels(int increment) { + this.pixelUnitIncrement = increment; + } + + public void setUnitIncrementInMillis(long increment) { + this.millsUnitIncrement = increment; + } + public void setSelected(boolean selected) { this.selected = selected; } @@ -98,10 +115,10 @@ graphics.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); } - int height = getHeight(); int currentValue = scrollPane.getHorizontalScrollBar().getValue(); - int totalInc = TimelineUtils.drawMarks(range, graphics, bounds, currentValue, getWidth(), height); - + int totalInc = pixelUnitIncrement; + TimelineUtils.drawMarks(range, graphics, bounds, currentValue, false, totalInc); + drawBoldMarks(graphics, currentValue, bounds, totalInc); Color lastColor = drawTimeline(graphics, currentValue, bounds); @@ -174,8 +191,8 @@ private void drawBoldMarks(Graphics2D graphics, int currentValue, Rectangle bounds, int totalInc) { - long round = range.getMin() % 10000; - int shift = (int) (round / TimelineUtils.STEP) * totalInc; + long round = range.getMin() % (10 * millsUnitIncrement); + int shift = (int) (round / millsUnitIncrement) * totalInc; int lowerBound = bounds.x - (4 * totalInc); int x = ((bounds.x - currentValue) - shift); @@ -204,7 +221,12 @@ @Override public int getWidth() { - return TimelineUtils.calculateWidth(range); + + long divisor = millsUnitIncrement / pixelUnitIncrement; + + long span = range.getMax() - range.getMin(); + int width = (int) (span / divisor); + return width; } @Override @@ -217,62 +239,5 @@ public Dimension getPreferredSize() { return new Dimension(getWidth(), getHeight()); } - - public static void main(String[] args) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - - LongRange range = new LongRange(50000, 2000000); // 31558464000L - Timeline timeline = new Timeline("Test", 1000); - timeline.add(new TimelineInfo(Palette.THERMOSTAT_BLU, range.getMax() - 1000)); - timeline.add(new TimelineInfo(Palette.TUNDRA_GREEN, 152000)); - timeline.add(new TimelineInfo(Palette.DIRTY_CYAN, 63000)); - timeline.add(new TimelineInfo(Palette.THERMOSTAT_BLU, 62000)); - timeline.add(new TimelineInfo(Palette.THERMOSTAT_RED, 60210)); - timeline.add(new TimelineInfo(Palette.THERMOSTAT_BLU, 51299)); - - final JFrame frame = new JFrame(); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - - - final JScrollPane scrollPane = new JScrollPane(); - DefaultListModel<TimelineComponent> chartModel = new DefaultListModel<>(); - for (int i = 0; i < 100; i++) { - chartModel.addElement(new TimelineComponent(range, timeline, scrollPane)); - } - - final JList<TimelineComponent> stuff = new JList<>(chartModel); - stuff.setCellRenderer(new TimelineCellRenderer()); - - scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); - scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); - scrollPane.getHorizontalScrollBar().setUnitIncrement(TimelineUtils.INC); - - final ThreadTimelineHeader header = new ThreadTimelineHeader(range, scrollPane); - - scrollPane.setColumnHeaderView(header); - scrollPane.setViewportView(stuff); - scrollPane.getVerticalScrollBar().getModel().addChangeListener(new ChangeListener() { - @Override - public void stateChanged(ChangeEvent e) { - scrollPane.repaint(); - } - }); - - scrollPane.getHorizontalScrollBar().getModel().addChangeListener(new ChangeListener() { - - @Override - public void stateChanged(ChangeEvent e) { - scrollPane.repaint(); - } - }); - - frame.add(scrollPane); - frame.setSize(300, 300); - frame.setVisible(true); - } - }); - } }
--- a/vm-heap-analysis/distribution/plugin.xml Thu Apr 25 11:28:32 2013 -0400 +++ b/vm-heap-analysis/distribution/plugin.xml Mon Apr 29 11:54:04 2013 -0400 @@ -47,14 +47,14 @@ <option> <long>hostId</long> <short>a</short> - <argument>true</argument> + <argument>host</argument> <required>true</required> <description>the ID of the host to monitor</description> </option> <option> <long>vmId</long> <short>v</short> - <argument>true</argument> + <argument>vm</argument> <required>true</required> <description>the ID of the VM to monitor</description> </option> @@ -91,18 +91,21 @@ <command> <name>find-objects</name> <description>finds objects in a heapdump</description> + <arguments> + <argument>pattern</argument> + </arguments> <options> <option> <long>heapId</long> <short>h</short> - <argument>true</argument> + <argument>heap</argument> <required>true</required> <description>the ID of the heapdump to analyze</description> </option> <option> <long>limit</long> <short>L</short> - <argument>true</argument> + <argument>limit</argument> <required>false</required> <description>limit search to top N results, defaults to 10</description> </option> @@ -143,21 +146,20 @@ <option> <long>heapId</long> <short>h</short> - <argument>true</argument> + <argument>heap</argument> <required>true</required> <description>the ID of the heapdump to analyze</description> </option> <option> <long>objectId</long> <short>o</short> - <argument>true</argument> + <argument>heap</argument> <required>true</required> <description>the ID of the object to query</description> </option> <option> <long>all</long> <short>a</short> - <argument>false</argument> <required>false</required> <description>finds all paths to GC roots</description> </option> @@ -198,14 +200,14 @@ <option> <long>hostId</long> <short>a</short> - <argument>true</argument> + <argument>host</argument> <required>false</required> <description>the ID of the host to monitor</description> </option> <option> <long>vmId</long> <short>v</short> - <argument>true</argument> + <argument>vm</argument> <required>false</required> <description>the ID of the VM to monitor</description> </option> @@ -246,14 +248,14 @@ <option> <long>heapId</long> <short>h</short> - <argument>true</argument> + <argument>heap</argument> <required>true</required> <description>the ID of the heapdump to analyze</description> </option> <option> <long>objectId</long> <short>o</short> - <argument>true</argument> + <argument>object</argument> <required>true</required> <description>the ID of the object to query</description> </option> @@ -294,14 +296,14 @@ <option> <long>heapId</long> <short>h</short> - <argument>true</argument> + <argument>heap</argument> <required>true</required> <description>the ID of the heapdump to analyze</description> </option> <option> <long>file</long> <short>f</short> - <argument>true</argument> + <argument>filename</argument> <required>true</required> <description>the file name to save to</description> </option> @@ -342,7 +344,7 @@ <option> <long>heapId</long> <short>h</short> - <argument>true</argument> + <argument>heap</argument> <required>true</required> <description>the ID of the heapdump to analyze</description> </option>