# HG changeset patch # User Elliott Baron # Date 1357761570 18000 # Node ID 1e51015e63e5a970a3d6432cee575b584cb42ddf # Parent 0289117ee9ef4f8de4d3ee6132a4da25681ed1e2 Allow plugins to dynamically contribute output to vm-stat command This commit follows the previous commits that created agent and common bundles for the plugins we include with Thermostat. Currently the vm-stat command uses output from the VmCpuStatDAO and VmMemoryStatDAO, which are now contained in plugins. In order to not have core Thermostat rely on the presence of plugins, this commit introduces a VMStatPrintDelegate interface which plugins can implement to dynamically provide output to the vm-stat command. The end result is the same vm-stat output as before, but without dependencies on the vm-cpu-common and vm-memory-common bundles. In addition, other plugins can contribute columns of data to the command as well. Reviewed-by: omajid Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-January/005031.html diff -r 0289117ee9ef -r 1e51015e63e5 client/cli/pom.xml --- a/client/cli/pom.xml Tue Jan 08 16:50:11 2013 -0500 +++ b/client/cli/pom.xml Wed Jan 09 14:59:30 2013 -0500 @@ -99,18 +99,12 @@ org.osgi org.osgi.core + provided - - com.redhat.thermostat - thermostat-vm-cpu-common - ${project.version} - - - - com.redhat.thermostat - thermostat-vm-memory-common - ${project.version} + org.osgi + org.osgi.compendium + provided @@ -125,17 +119,15 @@ Red Hat, Inc. com.redhat.thermostat.client.cli.internal.Activator com.redhat.thermostat.client.cli + + com.redhat.thermostat.client.cli, + META_INF.services, com.redhat.thermostat.client.cli.internal, <_nouses>true - - - *,com.redhat.thermostat.vm.cpu.common;resolution:=optional, - com.redhat.thermostat.vm.memory.common;resolution:=optional - diff -r 0289117ee9ef -r 1e51015e63e5 client/cli/src/main/java/com/redhat/thermostat/client/cli/VMStatPrintDelegate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/VMStatPrintDelegate.java Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,76 @@ +/* + * 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 + * . + * + * 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.client.cli; + +import java.util.List; + +import com.redhat.thermostat.common.Ordered; +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.model.TimeStampedPojo; + +/** + * This interface should be implemented by plug-ins that would like to + * contribute data to the output of the vm-stat command. + */ +public interface VMStatPrintDelegate extends Ordered { + + /** + * Returns statistics gathered by this plug-in newer than the specified + * time stamp. + * @param ref - the VM whose statistics to return + * @param timeStampSince - the earliest time stamp to return statistics for + * @return a list of statistics newer than the time stamp + */ + public List getLatestStats(VmRef ref, long timeStampSince); + + /** + * Returns header names for columns this plug-in wishes to add to the + * vm-stat command. + * @param stat - the first stat returned by {@link #getLatestStats(VmRef, long)} + * @return a list of column headers to append to vm-stat output + */ + public List getHeaders(TimeStampedPojo stat); + + /** + * Returns a row of data for the specified statistic that corresponds to + * the columns returned by {@link #getHeaders(TimeStampedPojo)}. + * @param stat - the statistic to generate output for + * @return a row of text for this statistic separated by column + */ + public List getStatRow(TimeStampedPojo stat); + +} diff -r 0289117ee9ef -r 1e51015e63e5 client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/LocaleResources.java --- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/LocaleResources.java Tue Jan 08 16:50:11 2013 -0500 +++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/LocaleResources.java Wed Jan 09 14:59:30 2013 -0500 @@ -70,8 +70,6 @@ COLUMN_HEADER_VM_NAME, COLUMN_HEADER_VM_STATUS, COLUMN_HEADER_TIME, - COLUMN_HEADER_CPU_PERCENT, - COLUMN_HEADER_MEMORY_PATTERN, VM_STOP_TIME_RUNNING, VM_STATUS_ALIVE, diff -r 0289117ee9ef -r 1e51015e63e5 client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java --- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java Tue Jan 08 16:50:11 2013 -0500 +++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatCommand.java Wed Jan 09 14:59:30 2013 -0500 @@ -1,5 +1,5 @@ /* - * Copyright 2012 Red Hat, Inc. + * Copyright 2013 Red Hat, Inc. * * This file is part of Thermostat. * @@ -37,71 +37,81 @@ package com.redhat.thermostat.client.cli.internal; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; +import org.osgi.util.tracker.ServiceTracker; + +import com.redhat.thermostat.client.cli.VMStatPrintDelegate; import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.OrderedComparator; import com.redhat.thermostat.common.Timer; import com.redhat.thermostat.common.cli.CommandContext; import com.redhat.thermostat.common.cli.CommandException; import com.redhat.thermostat.common.cli.HostVMArguments; import com.redhat.thermostat.common.cli.SimpleCommand; import com.redhat.thermostat.common.dao.VmRef; -import com.redhat.thermostat.common.locale.Translate; import com.redhat.thermostat.common.utils.LoggingUtils; -import com.redhat.thermostat.common.utils.OSGIUtils; -import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; -import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; public class VMStatCommand extends SimpleCommand { - private static final Translate translator = LocaleResources.createLocalizer(); - private static final Logger log = LoggingUtils.getLogger(VMStatCommand.class); - private static final String CMD_NAME = "vm-stat"; - - private OSGIUtils serviceProvider; - + + private List delegates; + private BundleContext context; + public VMStatCommand() { - this(OSGIUtils.getInstance()); + this(FrameworkUtil.getBundle(VMStatCommand.class).getBundleContext()); } - VMStatCommand(OSGIUtils serviceProvider) { - this.serviceProvider = serviceProvider; + VMStatCommand(BundleContext context) { + this.context = context; + delegates = new CopyOnWriteArrayList<>(); + ServiceTracker tracker = new ServiceTracker(context, VMStatPrintDelegate.class.getName(), null) { + + public Object addingService(ServiceReference reference) { + VMStatPrintDelegate delegate = (VMStatPrintDelegate) super.addingService(reference); + delegates.add(delegate); + return delegate; + }; + + public void removedService(ServiceReference reference, Object service) { + delegates.remove(service); + super.removedService(reference, service); + }; + + }; + tracker.open(); } @Override public void run(final CommandContext ctx) throws CommandException { - VmCpuStatDAO vmCpuStatDAO = serviceProvider.getServiceAllowNull(VmCpuStatDAO.class); - if (vmCpuStatDAO == null) { - throw new CommandException(translator.localize(LocaleResources.VM_CPU_SERVICE_NOT_AVAILABLE)); - } - - VmMemoryStatDAO vmMemoryStatDAO = serviceProvider.getServiceAllowNull(VmMemoryStatDAO.class); - if (vmMemoryStatDAO == null) { - throw new CommandException(translator.localize(LocaleResources.VM_MEMORY_SERVICE_NOT_AVAILABLE)); - } - HostVMArguments hostVMArgs = new HostVMArguments(ctx.getArguments()); VmRef vm = hostVMArgs.getVM(); - final VMStatPrinter statPrinter = new VMStatPrinter(vm, vmCpuStatDAO, vmMemoryStatDAO, ctx.getConsole().getOutput()); + // Pass a copy of the delegates list to the printer + final VMStatPrinter statPrinter = new VMStatPrinter(vm, new ArrayList<>(delegates), ctx.getConsole().getOutput()); statPrinter.printStats(); boolean continuous = ctx.getArguments().hasArgument("continuous"); if (continuous) { startContinuousStats(ctx, statPrinter); } - - serviceProvider.ungetService(VmMemoryStatDAO.class, vmMemoryStatDAO); - serviceProvider.ungetService(VmCpuStatDAO.class, vmCpuStatDAO); } private void startContinuousStats(final CommandContext ctx, final VMStatPrinter statPrinter) { final CountDownLatch latch = new CountDownLatch(1); - ApplicationService appSvc = serviceProvider.getService(ApplicationService.class); + ServiceReference ref = context.getServiceReference(ApplicationService.class.getName()); + ApplicationService appSvc = (ApplicationService) context.getService(ref); Timer timer = appSvc.getTimerFactory().createTimer(); timer.setDelay(1); timer.setInitialDelay(1); @@ -133,6 +143,8 @@ } catch (InterruptedException e) { // Return immediately. } + + context.ungetService(ref); } @Override diff -r 0289117ee9ef -r 1e51015e63e5 client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatPrinter.java --- a/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatPrinter.java Tue Jan 08 16:50:11 2013 -0500 +++ b/client/cli/src/main/java/com/redhat/thermostat/client/cli/internal/VMStatPrinter.java Wed Jan 09 14:59:30 2013 -0500 @@ -1,5 +1,5 @@ /* - * Copyright 2012 Red Hat, Inc. + * Copyright 2013 Red Hat, Inc. * * This file is part of Thermostat. * @@ -38,70 +38,102 @@ import java.io.PrintStream; import java.text.DateFormat; -import java.text.DecimalFormat; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; -import com.redhat.thermostat.common.Size; +import com.redhat.thermostat.client.cli.VMStatPrintDelegate; +import com.redhat.thermostat.common.OrderedComparator; import com.redhat.thermostat.common.cli.TableRenderer; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.common.locale.Translate; import com.redhat.thermostat.storage.model.TimeStampedPojo; import com.redhat.thermostat.storage.model.TimeStampedPojoComparator; import com.redhat.thermostat.storage.model.TimeStampedPojoCorrelator; -import com.redhat.thermostat.storage.model.VmCpuStat; -import com.redhat.thermostat.storage.model.VmMemoryStat; -import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; -import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; class VMStatPrinter { private static final Translate translator = LocaleResources.createLocalizer(); - private static final String CPU_PERCENT = translator.localize(LocaleResources.COLUMN_HEADER_CPU_PERCENT); private static final String TIME = translator.localize(LocaleResources.COLUMN_HEADER_TIME); private VmRef vm; - private VmCpuStatDAO vmCpuStatDAO; - private VmMemoryStatDAO vmMemoryStatDAO; + private List delegates; private PrintStream out; - private TimeStampedPojoCorrelator correlator = new TimeStampedPojoCorrelator(2); + private TimeStampedPojoCorrelator correlator; private TableRenderer table; - private int numSpaces; + private int numCols; + private Map delegateInfo; - private long lastCpuStatTimeStamp = Long.MIN_VALUE; - private long lastMemoryStatTimeStamp = Long.MIN_VALUE; - - VMStatPrinter(VmRef vm, VmCpuStatDAO vmCpuStatDAO, VmMemoryStatDAO vmMemoryStatDAO, PrintStream out) { + VMStatPrinter(VmRef vm, List delegates, PrintStream out) { this.vm = vm; - this.vmCpuStatDAO = vmCpuStatDAO; - this.vmMemoryStatDAO = vmMemoryStatDAO; + this.delegates = delegates; this.out = out; + int numDelegates = delegates.size(); + this.delegateInfo = new HashMap<>(); + this.correlator = new TimeStampedPojoCorrelator(numDelegates); + + // Sort the delegates list + Collections.sort(delegates, new OrderedComparator<>()); + + for (VMStatPrintDelegate delegate : delegates) { + DelegateInfo info = new DelegateInfo(); + info.lastTimeStamp = Long.MIN_VALUE; + delegateInfo.put(delegate, info); + } } void printStats() { - List cpuStats = vmCpuStatDAO.getLatestVmCpuStats(vm, lastCpuStatTimeStamp); - List memStats = vmMemoryStatDAO.getLatestVmMemoryStats(vm, lastMemoryStatTimeStamp); - - lastCpuStatTimeStamp = getLatestTimeStamp(lastCpuStatTimeStamp, cpuStats); - lastMemoryStatTimeStamp = getLatestTimeStamp(lastMemoryStatTimeStamp, memStats); - - printStats(cpuStats, memStats); + List> allStats = new ArrayList<>(); + List allHeaders = new ArrayList<>(); + allHeaders.add(TIME); + + // Copy since we can remove elements in loop body + List delegatesCopy = new ArrayList<>(delegates); + for (VMStatPrintDelegate delegate : delegatesCopy) { + long timeStamp = delegateInfo.get(delegate).lastTimeStamp; + List latestStats = delegate.getLatestStats(vm, timeStamp); + if (latestStats == null || latestStats.isEmpty()) { + // Skipping delegate + delegates.remove(delegate); + } + else { + List headers = delegate.getHeaders(latestStats.get(0)); + if (headers == null || headers.isEmpty()) { + // Skipping delegate + delegates.remove(delegate); + } + else { + DelegateInfo info = delegateInfo.get(delegate); + info.colsPerDelegate = headers.size(); + allHeaders.addAll(headers); + allStats.add(latestStats); + info.lastTimeStamp = getLatestTimeStamp(timeStamp, latestStats); + } + } + } + + printStats(allStats, allHeaders); } void printUpdatedStats() { correlator.clear(); - List cpuStats = vmCpuStatDAO.getLatestVmCpuStats(vm, lastCpuStatTimeStamp); - List memStats = vmMemoryStatDAO.getLatestVmMemoryStats(vm, lastMemoryStatTimeStamp); + + List> allStats = new ArrayList<>(); + for (VMStatPrintDelegate delegate : delegates) { + DelegateInfo info = delegateInfo.get(delegate); + List latestStats = delegate.getLatestStats(vm, info.lastTimeStamp); + allStats.add(latestStats); + info.lastTimeStamp = getLatestTimeStamp(info.lastTimeStamp, latestStats); + } - lastCpuStatTimeStamp = getLatestTimeStamp(lastCpuStatTimeStamp, cpuStats); - lastMemoryStatTimeStamp = getLatestTimeStamp(lastMemoryStatTimeStamp, memStats); - - correlate(cpuStats, memStats); + correlate(allStats); printUpdatedStatsImpl(); } @@ -113,103 +145,79 @@ } } - private void printStats(List cpuStats, List memStats) { - correlate(cpuStats, memStats); - numSpaces = getNumSpaces(memStats); - int numColumns = numSpaces + 2; - table = new TableRenderer(numColumns); - printHeaders(memStats, numSpaces, numColumns, table); + private void printStats(List> allStats, List headers) { + correlate(allStats); + numCols = headers.size(); + table = new TableRenderer(numCols); + printHeaders(table, headers); printUpdatedStatsImpl(); } - private void printStats(int numSpaces, TableRenderer table, Iterator i) { - - TimeStampedPojoCorrelator.Correlation correlation = i.next(); + private void printStats(TableRenderer table, Iterator iter) { + TimeStampedPojoCorrelator.Correlation correlation = iter.next(); - VmCpuStat cpuStat = (VmCpuStat) correlation.get(0); - DecimalFormat format = new DecimalFormat("#0.0"); - String cpuLoad = cpuStat != null ? format.format(cpuStat.getCpuLoad()) : ""; - + String[] line = new String[numCols]; DateFormat dateFormat = DateFormat.getTimeInstance(); String time = dateFormat.format(new Date(correlation.getTimeStamp())); - - String[] memoryUsage = getMemoryUsage((VmMemoryStat) correlation.get(1), numSpaces); - - String[] line = new String[numSpaces + 2]; - System.arraycopy(memoryUsage, 0, line, 2, numSpaces); line[0] = time; - line[1] = cpuLoad; + + int off = 1; // time is first index + for (int i = 0; i < delegates.size(); i++) { + TimeStampedPojo stat = correlation.get(i); + VMStatPrintDelegate delegate = delegates.get(i); + if (stat == null) { + // Fill with blanks + DelegateInfo info = delegateInfo.get(delegate); + Arrays.fill(line, off, off + info.colsPerDelegate, ""); + off += info.colsPerDelegate; + } + else { + List data = delegate.getStatRow(stat); + if (data == null) { + throw new NullPointerException("Returned null stat row"); + } + else if (data.size() != delegateInfo.get(delegate).colsPerDelegate) { + throw new IllegalStateException("Delegate " + + delegate.toString() + " provided " + + delegateInfo.get(delegate).colsPerDelegate + + " column headers, but only " + data.size() + + " stat row values"); + } + else { + System.arraycopy(data.toArray(), 0, line, off, data.size()); + off += data.size(); + } + } + } + table.printLine(line); } - private void printHeaders(List memStats, int numSpaces, int numColumns, TableRenderer table) { - String[] spacesNames = getSpacesNames(memStats, numSpaces); - String[] headers = new String[numColumns]; - headers[0] = TIME; - headers[1] = CPU_PERCENT; - System.arraycopy(spacesNames, 0, headers, 2, numSpaces); - table.printLine(headers); - } - - private String[] getMemoryUsage(VmMemoryStat vmMemoryStat, int numSpaces) { - String[] memoryUsage = new String[numSpaces]; - if (vmMemoryStat == null) { - Arrays.fill(memoryUsage, ""); - return memoryUsage; - } - int i = 0; - for (VmMemoryStat.Generation gen : vmMemoryStat.getGenerations()) { - for (VmMemoryStat.Space space : gen.getSpaces()) { - memoryUsage[i] = Size.bytes(space.getUsed()).toString(); - i++; - } - } - return memoryUsage; + private void printHeaders(TableRenderer table, List headers) { + table.printLine(headers.toArray(new String[headers.size()])); } - private String[] getSpacesNames(List memStats, int numSpaces) { - if (numSpaces < 1) { - return new String[0]; - } - String[] spacesNames = new String[numSpaces]; - VmMemoryStat stat = memStats.get(0); - int i = 0; - for (VmMemoryStat.Generation gen : stat.getGenerations()) { - for (VmMemoryStat.Space space : gen.getSpaces()) { - spacesNames[i] = translator.localize(LocaleResources.COLUMN_HEADER_MEMORY_PATTERN, space.getName()); - i++; + private void correlate(List> allStats) { + int count = 0; + for (List stats : allStats) { + for(TimeStampedPojo cpuStat : stats) { + correlator.add(count, cpuStat); } - } - return spacesNames; - } - - private int getNumSpaces(List memStats) { - if (memStats.size() < 1) { - return 0; - } - VmMemoryStat stat = memStats.get(0); - int numSpaces = 0; - for (VmMemoryStat.Generation gen : stat.getGenerations()) { - numSpaces += gen.getSpaces().length; - } - return numSpaces; - } - - private void correlate(List cpuStats, List memStats) { - for(VmCpuStat cpuStat : cpuStats) { - correlator.add(0, cpuStat); - } - for (VmMemoryStat memStat : memStats) { - correlator.add(1, memStat); + count++; } } void printUpdatedStatsImpl() { Iterator iterator = correlator.iterator(); while (iterator.hasNext()) { - printStats(numSpaces, table, iterator); + printStats(table, iterator); } table.render(out); } + + private static class DelegateInfo { + int colsPerDelegate; + long lastTimeStamp; + } } diff -r 0289117ee9ef -r 1e51015e63e5 client/cli/src/main/resources/com/redhat/thermostat/client/cli/strings.properties --- a/client/cli/src/main/resources/com/redhat/thermostat/client/cli/strings.properties Tue Jan 08 16:50:11 2013 -0500 +++ b/client/cli/src/main/resources/com/redhat/thermostat/client/cli/strings.properties Wed Jan 09 14:59:30 2013 -0500 @@ -28,8 +28,6 @@ COLUMN_HEADER_VM_NAME = VM_NAME COLUMN_HEADER_VM_STATUS = STATUS COLUMN_HEADER_TIME = TIME -COLUMN_HEADER_CPU_PERCENT = %CPU -COLUMN_HEADER_MEMORY_PATTERN = MEM.{0} VM_STOP_TIME_RUNNING = VM_STATUS_ALIVE = RUNNING diff -r 0289117ee9ef -r 1e51015e63e5 client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ActivatorTest.java --- a/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ActivatorTest.java Tue Jan 08 16:50:11 2013 -0500 +++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/ActivatorTest.java Wed Jan 09 14:59:30 2013 -0500 @@ -1,5 +1,5 @@ /* - * Copyright 2012 Red Hat, Inc. + * Copyright 2013 Red Hat, Inc. * * This file is part of Thermostat. * @@ -58,10 +58,12 @@ @Test public void testCommandsRegistered() throws Exception { - // Need to mock FrameworkUtil to avoid NPE in ShellCommand's no-arg constructor + // Need to mock FrameworkUtil to avoid NPE in ShellCommand and + // VMStatCommand's no-arg constructors PowerMockito.mockStatic(FrameworkUtil.class); Bundle mockBundle = mock(Bundle.class); when(FrameworkUtil.getBundle(ShellCommand.class)).thenReturn(mockBundle); + when(FrameworkUtil.getBundle(VMStatCommand.class)).thenReturn(mockBundle); StubBundleContext ctx = new StubBundleContext(); when(mockBundle.getBundleContext()).thenReturn(ctx); diff -r 0289117ee9ef -r 1e51015e63e5 client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VmStatCommandTest.java --- a/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VmStatCommandTest.java Tue Jan 08 16:50:11 2013 -0500 +++ b/client/cli/src/test/java/com/redhat/thermostat/client/cli/internal/VmStatCommandTest.java Wed Jan 09 14:59:30 2013 -0500 @@ -1,5 +1,5 @@ /* - * Copyright 2012 Red Hat, Inc. + * Copyright 2013 Red Hat, Inc. * * This file is part of Thermostat. * @@ -40,11 +40,15 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.TimeZone; @@ -59,26 +63,21 @@ import org.junit.Ignore; import org.junit.Test; +import com.redhat.thermostat.client.cli.VMStatPrintDelegate; import com.redhat.thermostat.common.ApplicationService; import com.redhat.thermostat.common.Timer; import com.redhat.thermostat.common.cli.CommandException; import com.redhat.thermostat.common.cli.SimpleArguments; -import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.common.dao.VmRef; -import com.redhat.thermostat.common.utils.OSGIUtils; -import com.redhat.thermostat.storage.model.VmCpuStat; -import com.redhat.thermostat.storage.model.VmMemoryStat; -import com.redhat.thermostat.storage.model.VmMemoryStat.Generation; -import com.redhat.thermostat.storage.model.VmMemoryStat.Space; +import com.redhat.thermostat.storage.model.TimeStampedPojo; +import com.redhat.thermostat.test.StubBundleContext; import com.redhat.thermostat.test.TestCommandContextFactory; import com.redhat.thermostat.test.TestTimerFactory; -import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; -import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; public class VmStatCommandTest { - private static Locale defaultLocale; private static TimeZone defaultTimeZone; + private static int NUM_ROWS = 3; @BeforeClass public static void setUpClass() { @@ -94,34 +93,62 @@ Locale.setDefault(defaultLocale); } - private VMStatCommand cmd; - private VmCpuStatDAO vmCpuStatDAO; + private VMStatPrintDelegate[] delegates; private TestCommandContextFactory cmdCtxFactory; - private VmMemoryStatDAO vmMemoryStatDAO; private TestTimerFactory timerFactory; + private ApplicationService appSvc; @Before public void setUp() { + delegates = new VMStatPrintDelegate[2]; + final String[][] headers = { + { "FIRST", "SECOND", "THIRD" }, + { "FOURTH", "FIFTH" } }; + + final String[][][] rows = { + { + { "1", "2", "3" }, + { "6", "7", "8" }, + { "11", "12", "13" }, + }, + { + { "4", "5" }, + { "9", "10" }, + { "14", "15" } + } + }; timerFactory = new TestTimerFactory(); - ApplicationService appSvc = mock(ApplicationService.class); + appSvc = mock(ApplicationService.class); when(appSvc.getTimerFactory()).thenReturn(timerFactory); setupCommandContextFactory(); - - setupDAOs(); - - OSGIUtils serviceProvider = mock(OSGIUtils.class); - when(serviceProvider.getServiceAllowNull(VmCpuStatDAO.class)).thenReturn(vmCpuStatDAO); - when(serviceProvider.getServiceAllowNull(VmMemoryStatDAO.class)).thenReturn(vmMemoryStatDAO); - when(serviceProvider.getService(ApplicationService.class)).thenReturn(appSvc); - - cmd = new VMStatCommand(serviceProvider); + + delegates[0] = mockDelegate(headers[0], rows[0]); + delegates[1] = mockDelegate(headers[1], rows[1]); + } + + private VMStatPrintDelegate mockDelegate(String[] headers, String[][] data) { + VMStatPrintDelegate delegate = mock(VMStatPrintDelegate.class); + List stats = new ArrayList<>(); + for (int i = 0; i < NUM_ROWS; i++) { + TimeStampedPojo stat = mock(TimeStampedPojo.class); + when(stat.getTimeStamp()).thenReturn(i * 1000L); // Increment by one second + stats.add(stat); + } + + // Need this syntax due to generics + doReturn(stats).when(delegate).getLatestStats(any(VmRef.class), eq(Long.MIN_VALUE)); + when(delegate.getHeaders(stats.get(0))).thenReturn(Arrays.asList(headers)); + for (int i = 0; i < data.length; i++) { + List row = Arrays.asList(data[i]); + doReturn(row).when(delegate).getStatRow(eq(stats.get(i))); + } + + return delegate; } @After public void tearDown() { - vmCpuStatDAO = null; cmdCtxFactory = null; - cmd = null; timerFactory = null; } @@ -129,116 +156,62 @@ cmdCtxFactory = new TestCommandContextFactory(); } - private void setupDAOs() { - vmCpuStatDAO = mock(VmCpuStatDAO.class); - int vmId = 234; - HostRef host = new HostRef("123", "dummy"); - VmRef vm = new VmRef(host, 234, "dummy"); - VmCpuStat cpustat1 = new VmCpuStat(2, vmId, 65); - VmCpuStat cpustat2 = new VmCpuStat(3, vmId, 70); - List cpuStats = Arrays.asList(cpustat1, cpustat2); - List cpuStats2 = Collections.emptyList(); - when(vmCpuStatDAO.getLatestVmCpuStats(vm, Long.MIN_VALUE)).thenReturn(cpuStats).thenReturn(cpuStats2); - - VmMemoryStat.Space space1_1_1 = newSpace("space1", 123456, 12345, 1, 0); - VmMemoryStat.Space space1_1_2 = newSpace("space2", 123456, 12345, 1, 0); - VmMemoryStat.Space[] spaces1_1 = new VmMemoryStat.Space[] { space1_1_1, space1_1_2 }; - VmMemoryStat.Generation gen1_1 = newGeneration("gen1", "col1", 123456, 12345, spaces1_1); - - VmMemoryStat.Space space1_2_1 = newSpace("space3", 123456, 12345, 1, 0); - VmMemoryStat.Space space1_2_2 = newSpace("space4", 123456, 12345, 1, 0); - VmMemoryStat.Space[] spaces1_2 = new VmMemoryStat.Space[] { space1_2_1, space1_2_2 }; - VmMemoryStat.Generation gen1_2 = newGeneration("gen2", "col1", 123456, 12345, spaces1_2); - - VmMemoryStat.Generation[] gens1 = new VmMemoryStat.Generation[] { gen1_1, gen1_2 }; - - VmMemoryStat memStat1 = new VmMemoryStat(1, vmId, gens1); - - VmMemoryStat.Space space2_1_1 = newSpace("space1", 123456, 12345, 2, 0); - VmMemoryStat.Space space2_1_2 = newSpace("space2", 123456, 12345, 2, 0); - VmMemoryStat.Space[] spaces2_1 = new VmMemoryStat.Space[] { space2_1_1, space2_1_2 }; - VmMemoryStat.Generation gen2_1 = newGeneration("gen1", "col1", 123456, 12345, spaces2_1); - - VmMemoryStat.Space space2_2_1 = newSpace("space3", 123456, 12345, 3, 0); - VmMemoryStat.Space space2_2_2 = newSpace("space4", 123456, 12345, 4, 0); - VmMemoryStat.Space[] spaces2_2 = new VmMemoryStat.Space[] { space2_2_1, space2_2_2 }; - VmMemoryStat.Generation gen2_2 = newGeneration("gen2", "col1", 123456, 12345, spaces2_2); - - VmMemoryStat.Generation[] gens2 = new VmMemoryStat.Generation[] { gen2_1, gen2_2 }; - - VmMemoryStat memStat2 = new VmMemoryStat(2, vmId, gens2); - - VmMemoryStat.Space space3_1_1 = newSpace("space1", 123456, 12345, 4, 0); - VmMemoryStat.Space space3_1_2 = newSpace("space2", 123456, 12345, 5, 0); - VmMemoryStat.Space[] spaces3_1 = new VmMemoryStat.Space[] { space3_1_1, space3_1_2 }; - VmMemoryStat.Generation gen3_1 = newGeneration("gen1", "col1", 123456, 12345, spaces3_1); - - VmMemoryStat.Space space3_2_1 = newSpace("space3", 123456, 12345, 6, 0); - VmMemoryStat.Space space3_2_2 = newSpace("space4", 123456, 12345, 7, 0); - VmMemoryStat.Space[] spaces3_2 = new VmMemoryStat.Space[] { space3_2_1, space3_2_2 }; - VmMemoryStat.Generation gen3_2 = newGeneration("gen2", "col1", 123456, 12345, spaces3_2); - - VmMemoryStat.Generation[] gens3 = new VmMemoryStat.Generation[] { gen3_1, gen3_2 }; - - VmMemoryStat memStat3 = new VmMemoryStat(3, vmId, gens3); - - VmMemoryStat.Space space4_1_1 = newSpace("space1", 123456, 12345, 8, 0); - VmMemoryStat.Space space4_1_2 = newSpace("space2", 123456, 12345, 9, 0); - VmMemoryStat.Space[] spaces4_1 = new VmMemoryStat.Space[] { space4_1_1, space4_1_2 }; - VmMemoryStat.Generation gen4_1 = newGeneration("gen4", "col1", 123456, 12345, spaces4_1); - - VmMemoryStat.Space space4_2_1 = newSpace("space3", 123456, 12345, 10, 0); - VmMemoryStat.Space space4_2_2 = newSpace("space4", 123456, 12345, 11, 0); - VmMemoryStat.Space[] spaces4_2 = new VmMemoryStat.Space[] { space4_2_1, space4_2_2 }; - VmMemoryStat.Generation gen4_2 = newGeneration("gen4", "col1", 123456, 12345, spaces4_2); - - VmMemoryStat.Generation[] gens4 = new VmMemoryStat.Generation[] { gen4_1, gen4_2 }; - - VmMemoryStat memStat4 = new VmMemoryStat(4, vmId, gens4); - - vmMemoryStatDAO = mock(VmMemoryStatDAO.class); - when(vmMemoryStatDAO.getLatestVmMemoryStats(vm, Long.MIN_VALUE)) - .thenReturn(Arrays.asList(memStat1, memStat2, memStat3)); - - when(vmMemoryStatDAO.getLatestVmMemoryStats(vm, memStat3.getTimeStamp())).thenReturn(Arrays.asList(memStat4)); - + @Test + public void testOutput() throws CommandException { + StubBundleContext context = new StubBundleContext(); + context.registerService(VMStatPrintDelegate.class.getName(), delegates[0], null); + context.registerService(VMStatPrintDelegate.class.getName(), delegates[1], null); + + VMStatCommand cmd = new VMStatCommand(context); + + SimpleArguments args = new SimpleArguments(); + args.addArgument("vmId", "234"); + args.addArgument("hostId", "123"); + cmd.run(cmdCtxFactory.createContext(args)); + String expected = "TIME FIRST SECOND THIRD FOURTH FIFTH\n" + + "12:00:00 AM 1 2 3 4 5\n" + + "12:00:01 AM 6 7 8 9 10\n" + + "12:00:02 AM 11 12 13 14 15\n"; + assertEquals(expected, cmdCtxFactory.getOutput()); } - - private Space newSpace(String name, long maxCapacity, long capacity, long used, int index) { - VmMemoryStat.Space space = new VmMemoryStat.Space(); - space.setName(name); - space.setMaxCapacity(maxCapacity); - space.setCapacity(capacity); - space.setUsed(used); - space.setIndex(index); - return space; - } - - private Generation newGeneration(String name, String collector, long maxCapacity, long capacity, Space[] spaces) { - VmMemoryStat.Generation gen = new VmMemoryStat.Generation(); - gen.setName(name); - gen.setCollector(collector); - gen.setMaxCapacity(capacity); - gen.setSpaces(spaces); - return gen; - } - + @Test - public void testBasicCPUMemory() throws CommandException { + public void testNoDelegates() throws CommandException { + StubBundleContext context = new StubBundleContext(); + VMStatCommand cmd = new VMStatCommand(context); + SimpleArguments args = new SimpleArguments(); args.addArgument("vmId", "234"); args.addArgument("hostId", "123"); cmd.run(cmdCtxFactory.createContext(args)); - String expected = "TIME %CPU MEM.space1 MEM.space2 MEM.space3 MEM.space4\n" + - "12:00:00 AM 1 B 1 B 1 B 1 B\n" + - "12:00:00 AM 65.0 2 B 2 B 3 B 4 B\n" + - "12:00:00 AM 70.0 4 B 5 B 6 B 7 B\n"; + String expected = "TIME\n"; assertEquals(expected, cmdCtxFactory.getOutput()); - } @Test public void testContinuousMode() throws CommandException { + final String[][] data = { + { "16", "17", "18" }, + { "19", "20" } + }; + StubBundleContext context = new StubBundleContext(); + context.registerService(ApplicationService.class.getName(), appSvc, null); + context.registerService(VMStatPrintDelegate.class.getName(), delegates[0], null); + context.registerService(VMStatPrintDelegate.class.getName(), delegates[1], null); + + // Add one more stat + TimeStampedPojo stat = mock(TimeStampedPojo.class); + // One second after previous timestamps + when(stat.getTimeStamp()).thenReturn(3000L); + List stats = new ArrayList<>(); + stats.add(stat); + + doReturn(stats).when(delegates[0]).getLatestStats(any(VmRef.class), eq(2000L)); + doReturn(stats).when(delegates[1]).getLatestStats(any(VmRef.class), eq(2000L)); + doReturn(Arrays.asList(data[0])).when(delegates[0]).getStatRow(eq(stat)); + doReturn(Arrays.asList(data[1])).when(delegates[1]).getStatRow(eq(stat)); + + final VMStatCommand cmd = new VMStatCommand(context); Thread t = new Thread() { public void run() { @@ -261,10 +234,10 @@ return; } assertTrue(timerFactory.isActive()); - String expected = "TIME %CPU MEM.space1 MEM.space2 MEM.space3 MEM.space4\n" + - "12:00:00 AM 1 B 1 B 1 B 1 B\n" + - "12:00:00 AM 65.0 2 B 2 B 3 B 4 B\n" + - "12:00:00 AM 70.0 4 B 5 B 6 B 7 B\n"; + String expected = "TIME FIRST SECOND THIRD FOURTH FIFTH\n" + + "12:00:00 AM 1 2 3 4 5\n" + + "12:00:01 AM 6 7 8 9 10\n" + + "12:00:02 AM 11 12 13 14 15\n"; assertEquals(expected, cmdCtxFactory.getOutput()); assertEquals(1, timerFactory.getDelay()); assertEquals(1, timerFactory.getInitialDelay()); @@ -273,11 +246,11 @@ timerFactory.getAction().run(); - expected = "TIME %CPU MEM.space1 MEM.space2 MEM.space3 MEM.space4\n" + - "12:00:00 AM 1 B 1 B 1 B 1 B\n" + - "12:00:00 AM 65.0 2 B 2 B 3 B 4 B\n" + - "12:00:00 AM 70.0 4 B 5 B 6 B 7 B\n" + - "12:00:00 AM 70.0 8 B 9 B 10 B 11 B\n"; + expected = "TIME FIRST SECOND THIRD FOURTH FIFTH\n" + + "12:00:00 AM 1 2 3 4 5\n" + + "12:00:01 AM 6 7 8 9 10\n" + + "12:00:02 AM 11 12 13 14 15\n" + + "12:00:03 AM 16 17 18 19 20\n"; assertEquals(expected, cmdCtxFactory.getOutput()); cmdCtxFactory.setInput(" "); try { @@ -290,18 +263,24 @@ @Test public void testName() { + StubBundleContext context = new StubBundleContext(); + VMStatCommand cmd = new VMStatCommand(context); assertEquals("vm-stat", cmd.getName()); } @Test public void testDescAndUsage() { - assertNotNull(cmd.getUsage()); + StubBundleContext context = new StubBundleContext(); + VMStatCommand cmd = new VMStatCommand(context); + assertNotNull(cmd.getDescription()); assertNotNull(cmd.getUsage()); } @Ignore @Test public void testOptions() { + StubBundleContext context = new StubBundleContext(); + VMStatCommand cmd = new VMStatCommand(context); Options options = cmd.getOptions(); assertNotNull(options); assertEquals(3, options.getOptions().size()); @@ -325,9 +304,91 @@ assertFalse(cont.isRequired()); assertFalse(cont.hasArg()); } + + @Test + public void testNoStats() throws CommandException { + // Fail stats != null check + VMStatPrintDelegate badDelegate = mock(VMStatPrintDelegate.class); + when(badDelegate.getLatestStats(any(VmRef.class), anyLong())).thenReturn(null); + + StubBundleContext context = new StubBundleContext(); + context.registerService(VMStatPrintDelegate.class, delegates[0], null); + context.registerService(VMStatPrintDelegate.class, badDelegate, null); + context.registerService(VMStatPrintDelegate.class, delegates[1], null); + + VMStatCommand cmd = new VMStatCommand(context); + + SimpleArguments args = new SimpleArguments(); + args.addArgument("vmId", "234"); + args.addArgument("hostId", "123"); + cmd.run(cmdCtxFactory.createContext(args)); + String expected = "TIME FIRST SECOND THIRD FOURTH FIFTH\n" + + "12:00:00 AM 1 2 3 4 5\n" + + "12:00:01 AM 6 7 8 9 10\n" + + "12:00:02 AM 11 12 13 14 15\n"; + assertEquals(expected, cmdCtxFactory.getOutput()); + } + + @Test + public void testNoHeaders() throws CommandException { + // Pass stats check, but fail headers check + VMStatPrintDelegate badDelegate = mock(VMStatPrintDelegate.class); + TimeStampedPojo stat = mock(TimeStampedPojo.class); + doReturn(Arrays.asList(stat)).when(badDelegate).getLatestStats(any(VmRef.class), anyLong()); + when(badDelegate.getHeaders(any(TimeStampedPojo.class))).thenReturn(null); + + StubBundleContext context = new StubBundleContext(); + context.registerService(VMStatPrintDelegate.class, delegates[0], null); + context.registerService(VMStatPrintDelegate.class, badDelegate, null); + context.registerService(VMStatPrintDelegate.class, delegates[1], null); + + VMStatCommand cmd = new VMStatCommand(context); + + SimpleArguments args = new SimpleArguments(); + args.addArgument("vmId", "234"); + args.addArgument("hostId", "123"); + cmd.run(cmdCtxFactory.createContext(args)); + String expected = "TIME FIRST SECOND THIRD FOURTH FIFTH\n" + + "12:00:00 AM 1 2 3 4 5\n" + + "12:00:01 AM 6 7 8 9 10\n" + + "12:00:02 AM 11 12 13 14 15\n"; + assertEquals(expected, cmdCtxFactory.getOutput()); + } + + @Test + public void testUnevenStat() throws CommandException { + // Fewer stats than other delegates + VMStatPrintDelegate badDelegate = mock(VMStatPrintDelegate.class); + TimeStampedPojo stat1 = mock(TimeStampedPojo.class); + when(stat1.getTimeStamp()).thenReturn(1000L); + TimeStampedPojo stat2 = mock(TimeStampedPojo.class); + when(stat2.getTimeStamp()).thenReturn(2000L); + doReturn(Arrays.asList(stat1, stat2)).when(badDelegate).getLatestStats(any(VmRef.class), anyLong()); + when(badDelegate.getHeaders(any(TimeStampedPojo.class))).thenReturn(Arrays.asList("BAD")); + when(badDelegate.getStatRow(any(TimeStampedPojo.class))).thenReturn(Arrays.asList("0")); + + StubBundleContext context = new StubBundleContext(); + context.registerService(VMStatPrintDelegate.class, delegates[0], null); + context.registerService(VMStatPrintDelegate.class, badDelegate, null); + context.registerService(VMStatPrintDelegate.class, delegates[1], null); + + VMStatCommand cmd = new VMStatCommand(context); + + SimpleArguments args = new SimpleArguments(); + args.addArgument("vmId", "234"); + args.addArgument("hostId", "123"); + cmd.run(cmdCtxFactory.createContext(args)); + String expected = "TIME FIRST SECOND THIRD BAD FOURTH FIFTH\n" + + "12:00:00 AM 1 2 3 4 5\n" + + "12:00:01 AM 6 7 8 0 9 10\n" + + "12:00:02 AM 11 12 13 0 14 15\n"; + assertEquals(expected, cmdCtxFactory.getOutput()); + } @Test public void testStorageRequired() { + StubBundleContext context = new StubBundleContext(); + VMStatCommand cmd = new VMStatCommand(context); assertTrue(cmd.isStorageRequired()); } } diff -r 0289117ee9ef -r 1e51015e63e5 common/core/src/main/java/com/redhat/thermostat/test/StubBundleContext.java --- a/common/core/src/main/java/com/redhat/thermostat/test/StubBundleContext.java Tue Jan 08 16:50:11 2013 -0500 +++ b/common/core/src/main/java/com/redhat/thermostat/test/StubBundleContext.java Wed Jan 09 14:59:30 2013 -0500 @@ -1,5 +1,5 @@ /* - * Copyright 2012 Red Hat, Inc. + * Copyright 2013 Red Hat, Inc. * * This file is part of Thermostat. * @@ -203,7 +203,13 @@ @Override public ServiceReference getServiceReference(String clazz) { - throw new NotImplementedException(); + ServiceReference result = null; + for (ServiceInformation info : registeredServices) { + if (info.serviceInterface.equals(clazz)) { + result = new StubServiceReference(info); + } + } + return result; } @Override diff -r 0289117ee9ef -r 1e51015e63e5 distribution/config/commands/vm-stat.properties --- a/distribution/config/commands/vm-stat.properties Tue Jan 08 16:50:11 2013 -0500 +++ b/distribution/config/commands/vm-stat.properties Wed Jan 09 14:59:30 2013 -0500 @@ -1,6 +1,8 @@ bundles = thermostat-client-cli-${project.version}.jar, \ thermostat-vm-cpu-common-${project.version}.jar, \ + thermostat-vm-cpu-client-cli-${project.version}.jar, \ thermostat-vm-memory-common-${project.version}.jar, \ + thermostat-vm-memory-client-cli-${project.version}.jar, \ thermostat-storage-mongodb-${project.version}.jar, \ thermostat-web-common-${project.version}.jar, \ thermostat-web-client-${project.version}.jar, \ diff -r 0289117ee9ef -r 1e51015e63e5 distribution/pom.xml --- a/distribution/pom.xml Tue Jan 08 16:50:11 2013 -0500 +++ b/distribution/pom.xml Wed Jan 09 14:59:30 2013 -0500 @@ -412,6 +412,11 @@ com.redhat.thermostat + thermostat-vm-cpu-client-cli + ${project.version} + + + com.redhat.thermostat thermostat-vm-cpu-agent ${project.version} @@ -447,6 +452,11 @@ com.redhat.thermostat + thermostat-vm-memory-client-cli + ${project.version} + + + com.redhat.thermostat thermostat-vm-memory-agent ${project.version} diff -r 0289117ee9ef -r 1e51015e63e5 vm-cpu/client-cli/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/client-cli/pom.xml Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,77 @@ + + + 4.0.0 + + thermostat-vm-cpu + com.redhat.thermostat + 0.5.0-SNAPSHOT + + thermostat-vm-cpu-client-cli + bundle + Thermostat VM CPU CLI Client plugin + + + + org.apache.felix + maven-bundle-plugin + true + + + + com.redhat.thermostat.vm.cpu.client.cli.internal + + Red Hat, Inc. + com.redhat.thermostat.vm.cpu.client.cli.internal.Activator + com.redhat.thermostat.vm.cpu.client.cli + + <_nouses>true + + + + + + + + + junit + junit + test + + + org.mockito + mockito-core + test + + + org.osgi + org.osgi.core + provided + + + org.osgi + org.osgi.compendium + provided + + + com.redhat.thermostat + thermostat-common-core + ${project.version} + + + com.redhat.thermostat + thermostat-vm-cpu-common + ${project.version} + + + com.redhat.thermostat + thermostat-common-test + ${project.version} + test + + + com.redhat.thermostat + thermostat-client-cli + ${project.version} + + + diff -r 0289117ee9ef -r 1e51015e63e5 vm-cpu/client-cli/src/main/java/com/redhat/thermostat/vm/cpu/client/cli/internal/Activator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/client-cli/src/main/java/com/redhat/thermostat/vm/cpu/client/cli/internal/Activator.java Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,80 @@ +/* + * 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 + * . + * + * 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.vm.cpu.client.cli.internal; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.ServiceTracker; + +import com.redhat.thermostat.client.cli.VMStatPrintDelegate; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; + +public class Activator implements BundleActivator { + + private ServiceTracker tracker; + private ServiceRegistration reg; + + @Override + public void start(BundleContext context) throws Exception { + tracker = new ServiceTracker(context, VmCpuStatDAO.class.getName(), null) { + @Override + public Object addingService(ServiceReference reference) { + VmCpuStatDAO vmCpuStatDAO = (VmCpuStatDAO) super.addingService(reference); + VmCpuStatPrintDelegate delegate = new VmCpuStatPrintDelegate(vmCpuStatDAO); + reg = context.registerService(VMStatPrintDelegate.class.getName(), delegate, null); + return vmCpuStatDAO; + } + + @Override + public void removedService(ServiceReference reference, + Object service) { + reg.unregister(); + super.removedService(reference, service); + } + }; + + tracker.open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + tracker.close(); + } + +} diff -r 0289117ee9ef -r 1e51015e63e5 vm-cpu/client-cli/src/main/java/com/redhat/thermostat/vm/cpu/client/cli/internal/LocaleResources.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/client-cli/src/main/java/com/redhat/thermostat/vm/cpu/client/cli/internal/LocaleResources.java Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,51 @@ +/* + * 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 + * . + * + * 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.vm.cpu.client.cli.internal; + +import com.redhat.thermostat.common.locale.Translate; + +public enum LocaleResources { + + COLUMN_HEADER_CPU_PERCENT, + ; + + static final String RESOURCE_BUNDLE = "com.redhat.thermostat.vm.cpu.client.cli.strings"; + + public static Translate createLocalizer() { + return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class); + } +} diff -r 0289117ee9ef -r 1e51015e63e5 vm-cpu/client-cli/src/main/java/com/redhat/thermostat/vm/cpu/client/cli/internal/VmCpuStatPrintDelegate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/client-cli/src/main/java/com/redhat/thermostat/vm/cpu/client/cli/internal/VmCpuStatPrintDelegate.java Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,86 @@ +/* + * 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 + * . + * + * 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.vm.cpu.client.cli.internal; + +import java.text.DecimalFormat; +import java.util.Arrays; +import java.util.List; + +import com.redhat.thermostat.client.cli.VMStatPrintDelegate; +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.common.locale.Translate; +import com.redhat.thermostat.storage.model.TimeStampedPojo; +import com.redhat.thermostat.storage.model.VmCpuStat; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; + +public class VmCpuStatPrintDelegate implements VMStatPrintDelegate { + + private static final Translate translator = LocaleResources.createLocalizer(); + + private static final String CPU_PERCENT = translator.localize(LocaleResources.COLUMN_HEADER_CPU_PERCENT); + + private VmCpuStatDAO cpuStatDAO; + + public VmCpuStatPrintDelegate(VmCpuStatDAO cpuStatDAO) { + this.cpuStatDAO = cpuStatDAO; + } + + @Override + public List getLatestStats(VmRef ref, + long timestamp) { + return cpuStatDAO.getLatestVmCpuStats(ref, timestamp); + } + + @Override + public List getHeaders(TimeStampedPojo stat) { + return Arrays.asList(CPU_PERCENT); + } + + @Override + public List getStatRow(TimeStampedPojo stat) { + VmCpuStat cpuStat = (VmCpuStat) stat; + DecimalFormat format = new DecimalFormat("#0.0"); + String cpuLoad = cpuStat != null ? format.format(cpuStat.getCpuLoad()) : ""; + return Arrays.asList(cpuLoad); + } + + @Override + public int getOrderValue() { + return ORDER_CPU_GROUP; + } + +} diff -r 0289117ee9ef -r 1e51015e63e5 vm-cpu/client-cli/src/main/resources/com/redhat/thermostat/vm/cpu/client/cli/strings.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/client-cli/src/main/resources/com/redhat/thermostat/vm/cpu/client/cli/strings.properties Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,1 @@ +COLUMN_HEADER_CPU_PERCENT = %CPU \ No newline at end of file diff -r 0289117ee9ef -r 1e51015e63e5 vm-cpu/client-cli/src/test/java/com/redhat/thermostat/vm/cpu/client/cli/internal/ActivatorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/client-cli/src/test/java/com/redhat/thermostat/vm/cpu/client/cli/internal/ActivatorTest.java Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,84 @@ +/* + * 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 + * . + * + * 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.vm.cpu.client.cli.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import org.junit.Test; + +import com.redhat.thermostat.client.cli.VMStatPrintDelegate; +import com.redhat.thermostat.test.StubBundleContext; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; + +public class ActivatorTest { + + @Test + public void verifyActivatorDoesNotRegisterServiceOnMissingDeps() throws Exception { + StubBundleContext context = new StubBundleContext(); + + Activator activator = new Activator(); + + activator.start(context); + + assertEquals(0, context.getAllServices().size()); + assertEquals(1, context.getServiceListeners().size()); + + activator.stop(context); + } + + @Test + public void verifyActivatorRegistersServices() throws Exception { + StubBundleContext context = new StubBundleContext(); + VmCpuStatDAO dao = mock(VmCpuStatDAO.class); + + context.registerService(VmCpuStatDAO.class, dao, null); + + Activator activator = new Activator(); + + activator.start(context); + + assertTrue(context.isServiceRegistered(VMStatPrintDelegate.class.getName(), VmCpuStatPrintDelegate.class)); + + activator.stop(context); + + assertEquals(0, context.getServiceListeners().size()); + assertEquals(1, context.getAllServices().size()); + } + +} diff -r 0289117ee9ef -r 1e51015e63e5 vm-cpu/client-cli/src/test/java/com/redhat/thermostat/vm/cpu/client/cli/internal/LocaleResourcesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/client-cli/src/test/java/com/redhat/thermostat/vm/cpu/client/cli/internal/LocaleResourcesTest.java Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,53 @@ +/* + * 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 + * . + * + * 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.vm.cpu.client.cli.internal; + +import com.redhat.thermostat.test.locale.AbstractLocaleResourcesTest; + +public class LocaleResourcesTest extends AbstractLocaleResourcesTest { + + @Override + protected Class getEnumClass() { + return LocaleResources.class; + } + + @Override + protected String getResourceBundle() { + return LocaleResources.RESOURCE_BUNDLE; + } + +} diff -r 0289117ee9ef -r 1e51015e63e5 vm-cpu/client-cli/src/test/java/com/redhat/thermostat/vm/cpu/client/cli/internal/VmCpuStatPrintDelegateTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-cpu/client-cli/src/test/java/com/redhat/thermostat/vm/cpu/client/cli/internal/VmCpuStatPrintDelegateTest.java Wed Jan 09 14:59:30 2013 -0500 @@ -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 + * . + * + * 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.vm.cpu.client.cli.internal; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.model.TimeStampedPojo; +import com.redhat.thermostat.storage.model.VmCpuStat; +import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; + +public class VmCpuStatPrintDelegateTest { + + private VmCpuStatDAO vmCpuStatDAO; + private VmCpuStatPrintDelegate delegate; + private VmRef vm; + private List cpuStats; + + @Before + public void setUp() { + setupDAOs(); + delegate = new VmCpuStatPrintDelegate(vmCpuStatDAO); + } + + @After + public void tearDown() { + vmCpuStatDAO = null; + } + + private void setupDAOs() { + vmCpuStatDAO = mock(VmCpuStatDAO.class); + int vmId = 234; + HostRef host = new HostRef("123", "dummy"); + vm = new VmRef(host, 234, "dummy"); + VmCpuStat cpustat1 = new VmCpuStat(2, vmId, 65); + VmCpuStat cpustat2 = new VmCpuStat(3, vmId, 70); + cpuStats = Arrays.asList(cpustat1, cpustat2); + when(vmCpuStatDAO.getLatestVmCpuStats(vm, Long.MIN_VALUE)).thenReturn(cpuStats); + } + + @Test + public void testGetLatestStats() { + List stats = delegate.getLatestStats(vm, Long.MIN_VALUE); + assertEquals(cpuStats, stats); + } + + @Test + public void testGetHeaders() { + List headers = delegate.getHeaders(cpuStats.get(0)); + assertEquals(Arrays.asList("%CPU"), headers); + } + + @Test + public void testGetStatRow() throws CommandException { + final List row1 = Arrays.asList("65.0"); + final List row2 = Arrays.asList("70.0"); + assertEquals(row1, delegate.getStatRow(cpuStats.get(0))); + assertEquals(row2, delegate.getStatRow(cpuStats.get(1))); + } + +} diff -r 0289117ee9ef -r 1e51015e63e5 vm-cpu/pom.xml --- a/vm-cpu/pom.xml Tue Jan 08 16:50:11 2013 -0500 +++ b/vm-cpu/pom.xml Wed Jan 09 14:59:30 2013 -0500 @@ -52,6 +52,7 @@ agent + client-cli client-core client-swing common diff -r 0289117ee9ef -r 1e51015e63e5 vm-memory/client-cli/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-memory/client-cli/pom.xml Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,77 @@ + + + 4.0.0 + + thermostat-vm-memory + com.redhat.thermostat + 0.5.0-SNAPSHOT + + thermostat-vm-memory-client-cli + bundle + Thermostat VM Memory CLI Client plugin + + + + org.apache.felix + maven-bundle-plugin + true + + + + com.redhat.thermostat.vm.memory.client.cli.internal + + Red Hat, Inc. + com.redhat.thermostat.vm.memory.client.cli.internal.Activator + com.redhat.thermostat.vm.memory.client.cli + + <_nouses>true + + + + + + + + + junit + junit + test + + + org.mockito + mockito-core + test + + + org.osgi + org.osgi.core + provided + + + org.osgi + org.osgi.compendium + provided + + + com.redhat.thermostat + thermostat-common-core + ${project.version} + + + com.redhat.thermostat + thermostat-vm-memory-common + ${project.version} + + + com.redhat.thermostat + thermostat-common-test + ${project.version} + test + + + com.redhat.thermostat + thermostat-client-cli + ${project.version} + + + diff -r 0289117ee9ef -r 1e51015e63e5 vm-memory/client-cli/src/main/java/com/redhat/thermostat/vm/memory/client/cli/internal/Activator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-memory/client-cli/src/main/java/com/redhat/thermostat/vm/memory/client/cli/internal/Activator.java Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,80 @@ +/* + * 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 + * . + * + * 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.vm.memory.client.cli.internal; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.util.tracker.ServiceTracker; + +import com.redhat.thermostat.client.cli.VMStatPrintDelegate; +import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; + +public class Activator implements BundleActivator { + + private ServiceTracker tracker; + private ServiceRegistration reg; + + @Override + public void start(BundleContext context) throws Exception { + tracker = new ServiceTracker(context, VmMemoryStatDAO.class.getName(), null) { + @Override + public Object addingService(ServiceReference reference) { + VmMemoryStatDAO vmMemoryStatDAO = (VmMemoryStatDAO) super.addingService(reference); + VmMemoryStatPrintDelegate delegate = new VmMemoryStatPrintDelegate(vmMemoryStatDAO); + reg = context.registerService(VMStatPrintDelegate.class.getName(), delegate, null); + return vmMemoryStatDAO; + } + + @Override + public void removedService(ServiceReference reference, + Object service) { + reg.unregister(); + super.removedService(reference, service); + } + }; + + tracker.open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + tracker.close(); + } + +} diff -r 0289117ee9ef -r 1e51015e63e5 vm-memory/client-cli/src/main/java/com/redhat/thermostat/vm/memory/client/cli/internal/LocaleResources.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-memory/client-cli/src/main/java/com/redhat/thermostat/vm/memory/client/cli/internal/LocaleResources.java Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,53 @@ +/* + * 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 + * . + * + * 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.vm.memory.client.cli.internal; + +import com.redhat.thermostat.common.locale.Translate; + +public enum LocaleResources { + + VALUE_AND_UNIT, + + COLUMN_HEADER_MEMORY_PATTERN, + ; + + static final String RESOURCE_BUNDLE = "com.redhat.thermostat.vm.memory.client.cli.strings"; + + public static Translate createLocalizer() { + return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class); + } +} diff -r 0289117ee9ef -r 1e51015e63e5 vm-memory/client-cli/src/main/java/com/redhat/thermostat/vm/memory/client/cli/internal/VmMemoryStatPrintDelegate.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-memory/client-cli/src/main/java/com/redhat/thermostat/vm/memory/client/cli/internal/VmMemoryStatPrintDelegate.java Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,101 @@ +/* + * 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 + * . + * + * 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.vm.memory.client.cli.internal; + +import java.util.ArrayList; +import java.util.List; + +import com.redhat.thermostat.client.cli.VMStatPrintDelegate; +import com.redhat.thermostat.common.Size; +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.common.locale.Translate; +import com.redhat.thermostat.storage.model.TimeStampedPojo; +import com.redhat.thermostat.storage.model.VmMemoryStat; +import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; + +public class VmMemoryStatPrintDelegate implements VMStatPrintDelegate { + + private static final Translate translator = LocaleResources.createLocalizer(); + + private VmMemoryStatDAO memoryStatDAO; + + public VmMemoryStatPrintDelegate(VmMemoryStatDAO memoryStatDAO) { + this.memoryStatDAO = memoryStatDAO; + } + + @Override + public List getLatestStats(VmRef ref, long timestamp) { + return memoryStatDAO.getLatestVmMemoryStats(ref, timestamp); + } + + @Override + public List getHeaders(TimeStampedPojo stat) { + return getSpacesNames(stat); + } + + @Override + public List getStatRow(TimeStampedPojo stat) { + return getMemoryUsage(stat); + } + + private List getSpacesNames(TimeStampedPojo stat) { + List spacesNames = new ArrayList<>(); + VmMemoryStat memStat = (VmMemoryStat) stat; + for (VmMemoryStat.Generation gen : memStat.getGenerations()) { + for (VmMemoryStat.Space space : gen.getSpaces()) { + spacesNames.add(translator.localize(LocaleResources.COLUMN_HEADER_MEMORY_PATTERN, space.getName())); + } + } + return spacesNames; + } + + private List getMemoryUsage(TimeStampedPojo stat) { + List memoryUsage = new ArrayList<>(); + for (VmMemoryStat.Generation gen : ((VmMemoryStat) stat).getGenerations()) { + for (VmMemoryStat.Space space : gen.getSpaces()) { + memoryUsage.add(Size.bytes(space.getUsed()).toString()); + } + } + return memoryUsage; + } + + @Override + public int getOrderValue() { + return ORDER_MEMORY_GROUP; + } + +} diff -r 0289117ee9ef -r 1e51015e63e5 vm-memory/client-cli/src/main/resources/com/redhat/thermostat/vm/memory/client/cli/strings.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-memory/client-cli/src/main/resources/com/redhat/thermostat/vm/memory/client/cli/strings.properties Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,3 @@ +VALUE_AND_UNIT = {0} {1} + +COLUMN_HEADER_MEMORY_PATTERN = MEM.{0} \ No newline at end of file diff -r 0289117ee9ef -r 1e51015e63e5 vm-memory/client-cli/src/test/java/com/redhat/thermostat/vm/memory/client/cli/internal/ActivatorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-memory/client-cli/src/test/java/com/redhat/thermostat/vm/memory/client/cli/internal/ActivatorTest.java Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,84 @@ +/* + * 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 + * . + * + * 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.vm.memory.client.cli.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import org.junit.Test; + +import com.redhat.thermostat.client.cli.VMStatPrintDelegate; +import com.redhat.thermostat.test.StubBundleContext; +import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; + +public class ActivatorTest { + + @Test + public void verifyActivatorDoesNotRegisterServiceOnMissingDeps() throws Exception { + StubBundleContext context = new StubBundleContext(); + + Activator activator = new Activator(); + + activator.start(context); + + assertEquals(0, context.getAllServices().size()); + assertEquals(1, context.getServiceListeners().size()); + + activator.stop(context); + } + + @Test + public void verifyActivatorRegistersServices() throws Exception { + StubBundleContext context = new StubBundleContext(); + VmMemoryStatDAO dao = mock(VmMemoryStatDAO.class); + + context.registerService(VmMemoryStatDAO.class, dao, null); + + Activator activator = new Activator(); + + activator.start(context); + + assertTrue(context.isServiceRegistered(VMStatPrintDelegate.class.getName(), VmMemoryStatPrintDelegate.class)); + + activator.stop(context); + + assertEquals(0, context.getServiceListeners().size()); + assertEquals(1, context.getAllServices().size()); + } + +} diff -r 0289117ee9ef -r 1e51015e63e5 vm-memory/client-cli/src/test/java/com/redhat/thermostat/vm/memory/client/cli/internal/LocaleResourcesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-memory/client-cli/src/test/java/com/redhat/thermostat/vm/memory/client/cli/internal/LocaleResourcesTest.java Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,53 @@ +/* + * 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 + * . + * + * 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.vm.memory.client.cli.internal; + +import com.redhat.thermostat.test.locale.AbstractLocaleResourcesTest; + +public class LocaleResourcesTest extends AbstractLocaleResourcesTest { + + @Override + protected Class getEnumClass() { + return LocaleResources.class; + } + + @Override + protected String getResourceBundle() { + return LocaleResources.RESOURCE_BUNDLE; + } + +} diff -r 0289117ee9ef -r 1e51015e63e5 vm-memory/client-cli/src/test/java/com/redhat/thermostat/vm/memory/client/cli/internal/VmMemoryStatPrintDelegateTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-memory/client-cli/src/test/java/com/redhat/thermostat/vm/memory/client/cli/internal/VmMemoryStatPrintDelegateTest.java Wed Jan 09 14:59:30 2013 -0500 @@ -0,0 +1,172 @@ +/* + * 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 + * . + * + * 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.vm.memory.client.cli.internal; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.redhat.thermostat.client.cli.VMStatPrintDelegate; +import com.redhat.thermostat.common.cli.CommandException; +import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.storage.model.TimeStampedPojo; +import com.redhat.thermostat.storage.model.VmMemoryStat; +import com.redhat.thermostat.storage.model.VmMemoryStat.Generation; +import com.redhat.thermostat.storage.model.VmMemoryStat.Space; +import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; + +public class VmMemoryStatPrintDelegateTest { + + private VmMemoryStatDAO vmMemoryStatDAO; + private VMStatPrintDelegate delegate; + private VmRef vm; + private List memoryStats; + + @Before + public void setUp() { + setupDAOs(); + delegate = new VmMemoryStatPrintDelegate(vmMemoryStatDAO); + } + + @After + public void tearDown() { + vmMemoryStatDAO = null; + } + + private void setupDAOs() { + int vmId = 234; + HostRef host = new HostRef("123", "dummy"); + vm = new VmRef(host, 234, "dummy"); + + VmMemoryStat.Space space1_1_1 = newSpace("space1", 123456, 12345, 1, 0); + VmMemoryStat.Space space1_1_2 = newSpace("space2", 123456, 12345, 1, 0); + VmMemoryStat.Space[] spaces1_1 = new VmMemoryStat.Space[] { space1_1_1, space1_1_2 }; + VmMemoryStat.Generation gen1_1 = newGeneration("gen1", "col1", 123456, 12345, spaces1_1); + + VmMemoryStat.Space space1_2_1 = newSpace("space3", 123456, 12345, 1, 0); + VmMemoryStat.Space space1_2_2 = newSpace("space4", 123456, 12345, 1, 0); + VmMemoryStat.Space[] spaces1_2 = new VmMemoryStat.Space[] { space1_2_1, space1_2_2 }; + VmMemoryStat.Generation gen1_2 = newGeneration("gen2", "col1", 123456, 12345, spaces1_2); + + VmMemoryStat.Generation[] gens1 = new VmMemoryStat.Generation[] { gen1_1, gen1_2 }; + + VmMemoryStat memStat1 = new VmMemoryStat(1, vmId, gens1); + + VmMemoryStat.Space space2_1_1 = newSpace("space1", 123456, 12345, 2, 0); + VmMemoryStat.Space space2_1_2 = newSpace("space2", 123456, 12345, 2, 0); + VmMemoryStat.Space[] spaces2_1 = new VmMemoryStat.Space[] { space2_1_1, space2_1_2 }; + VmMemoryStat.Generation gen2_1 = newGeneration("gen1", "col1", 123456, 12345, spaces2_1); + + VmMemoryStat.Space space2_2_1 = newSpace("space3", 123456, 12345, 3, 0); + VmMemoryStat.Space space2_2_2 = newSpace("space4", 123456, 12345, 4, 0); + VmMemoryStat.Space[] spaces2_2 = new VmMemoryStat.Space[] { space2_2_1, space2_2_2 }; + VmMemoryStat.Generation gen2_2 = newGeneration("gen2", "col1", 123456, 12345, spaces2_2); + + VmMemoryStat.Generation[] gens2 = new VmMemoryStat.Generation[] { gen2_1, gen2_2 }; + + VmMemoryStat memStat2 = new VmMemoryStat(2, vmId, gens2); + + VmMemoryStat.Space space3_1_1 = newSpace("space1", 123456, 12345, 4, 0); + VmMemoryStat.Space space3_1_2 = newSpace("space2", 123456, 12345, 5, 0); + VmMemoryStat.Space[] spaces3_1 = new VmMemoryStat.Space[] { space3_1_1, space3_1_2 }; + VmMemoryStat.Generation gen3_1 = newGeneration("gen1", "col1", 123456, 12345, spaces3_1); + + VmMemoryStat.Space space3_2_1 = newSpace("space3", 123456, 12345, 6, 0); + VmMemoryStat.Space space3_2_2 = newSpace("space4", 123456, 12345, 7, 0); + VmMemoryStat.Space[] spaces3_2 = new VmMemoryStat.Space[] { space3_2_1, space3_2_2 }; + VmMemoryStat.Generation gen3_2 = newGeneration("gen2", "col1", 123456, 12345, spaces3_2); + + VmMemoryStat.Generation[] gens3 = new VmMemoryStat.Generation[] { gen3_1, gen3_2 }; + + VmMemoryStat memStat3 = new VmMemoryStat(3, vmId, gens3); + + vmMemoryStatDAO = mock(VmMemoryStatDAO.class); + memoryStats = Arrays.asList(memStat1, memStat2, memStat3); + when(vmMemoryStatDAO.getLatestVmMemoryStats(vm, Long.MIN_VALUE)) + .thenReturn(memoryStats); + } + + private Space newSpace(String name, long maxCapacity, long capacity, long used, int index) { + VmMemoryStat.Space space = new VmMemoryStat.Space(); + space.setName(name); + space.setMaxCapacity(maxCapacity); + space.setCapacity(capacity); + space.setUsed(used); + space.setIndex(index); + return space; + } + + private Generation newGeneration(String name, String collector, long maxCapacity, long capacity, Space[] spaces) { + VmMemoryStat.Generation gen = new VmMemoryStat.Generation(); + gen.setName(name); + gen.setCollector(collector); + gen.setMaxCapacity(capacity); + gen.setSpaces(spaces); + return gen; + } + + @Test + public void testGetLatestStats() { + List stats = delegate.getLatestStats(vm, Long.MIN_VALUE); + assertEquals(memoryStats, stats); + } + + @Test + public void testGetHeaders() { + List headers = delegate.getHeaders(memoryStats.get(0)); + assertEquals(Arrays.asList("MEM.space1", "MEM.space2", "MEM.space3", "MEM.space4"), headers); + } + + @Test + public void testGetStatRow() throws CommandException { + final List row1 = Arrays.asList("1 B", "1 B", "1 B", "1 B"); + final List row2 = Arrays.asList("2 B", "2 B", "3 B", "4 B"); + final List row3 = Arrays.asList("4 B", "5 B", "6 B", "7 B"); + assertEquals(row1, delegate.getStatRow(memoryStats.get(0))); + assertEquals(row2, delegate.getStatRow(memoryStats.get(1))); + assertEquals(row3, delegate.getStatRow(memoryStats.get(2))); + } + +} diff -r 0289117ee9ef -r 1e51015e63e5 vm-memory/pom.xml --- a/vm-memory/pom.xml Tue Jan 08 16:50:11 2013 -0500 +++ b/vm-memory/pom.xml Wed Jan 09 14:59:30 2013 -0500 @@ -52,6 +52,7 @@ agent + client-cli client-core client-swing common