# HG changeset patch # User Roman Kennke # Date 1358867688 -3600 # Node ID 8a6697503832cbe98eb871be88d1d98a0f464df1 # Parent ce04776b8b818fbfdf8e91174cfea056d7acbce8 Initial NUMA Swing client. Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-January/005282.html diff -r ce04776b8b81 -r 8a6697503832 distribution/config/commands/gui.properties --- a/distribution/config/commands/gui.properties Fri Jan 18 18:43:12 2013 +0100 +++ b/distribution/config/commands/gui.properties Tue Jan 22 16:14:48 2013 +0100 @@ -49,6 +49,9 @@ thermostat-gc-remote-collector-client-common-@project.version@.jar, \ thermostat-gc-remote-collector-client-swing-@project.version@.jar, \ thermostat-osgi-process-handler-@project.version@.jar, \ + thermostat-numa-common-@project.version@.jar, \ + thermostat-numa-client-core-@project.version@.jar, \ + thermostat-numa-client-swing-@project.version@.jar, \ httpcomponents-core.jar, \ httpcomponents-client.jar, \ netty.jar diff -r ce04776b8b81 -r 8a6697503832 distribution/pom.xml --- a/distribution/pom.xml Fri Jan 18 18:43:12 2013 +0100 +++ b/distribution/pom.xml Tue Jan 22 16:14:48 2013 +0100 @@ -596,5 +596,10 @@ thermostat-numa-agent ${project.version} + + com.redhat.thermostat + thermostat-numa-client-swing + ${project.version} + diff -r ce04776b8b81 -r 8a6697503832 numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaBackend.java --- a/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaBackend.java Fri Jan 18 18:43:12 2013 +0100 +++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaBackend.java Tue Jan 22 16:14:48 2013 +0100 @@ -79,6 +79,9 @@ @Override public boolean activate() { + int numNodes = numaCollector.getNumberOfNumaNodes(); + numaDAO.putNumberOfNumaNodes(numNodes); + TimerFactory timerFactory = appService.getTimerFactory(); timer = timerFactory.createTimer(); timer.setDelay(NUMA_CHECK_INTERVAL_SECONDS); diff -r ce04776b8b81 -r 8a6697503832 numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaCollector.java --- a/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaCollector.java Fri Jan 18 18:43:12 2013 +0100 +++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaCollector.java Tue Jan 22 16:14:48 2013 +0100 @@ -94,4 +94,8 @@ String getBaseDir() { return baseDir.getAbsolutePath(); } + + public int getNumberOfNumaNodes() { + return numberOfNodes; + } } diff -r ce04776b8b81 -r 8a6697503832 numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaBackendTest.java --- a/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaBackendTest.java Fri Jan 18 18:43:12 2013 +0100 +++ b/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaBackendTest.java Tue Jan 22 16:14:48 2013 +0100 @@ -106,6 +106,7 @@ NumaNodeStat stat2 = mock(NumaNodeStat.class); NumaNodeStat[] stats = new NumaNodeStat[] { stat1, stat2 }; when(collector.collectData()).thenReturn(stats); + when(collector.getNumberOfNumaNodes()).thenReturn(42); ArgumentCaptor statCaptor = ArgumentCaptor.forClass(NumaStat.class); doNothing().when(numaDAO).putNumaStat(statCaptor.capture()); @@ -121,8 +122,10 @@ verifyNoMoreInteractions(timer); Runnable action = actionCaptor.getValue(); - verifyZeroInteractions(numaDAO); - verifyZeroInteractions(collector); + verify(numaDAO).putNumberOfNumaNodes(42); + verifyNoMoreInteractions(numaDAO); + verify(collector).getNumberOfNumaNodes(); + verifyNoMoreInteractions(collector); action.run(); verify(collector).collectData(); diff -r ce04776b8b81 -r 8a6697503832 numa/client-core/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-core/pom.xml Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,80 @@ + + + 4.0.0 + + thermostat-numa + com.redhat.thermostat + 0.5.0-SNAPSHOT + + thermostat-numa-client-core + bundle + Thermostat NUMA Core Client plugin + + + + org.apache.felix + maven-bundle-plugin + true + + + Red Hat, Inc. + com.redhat.thermostat.numa.client.core + com.redhat.thermostat.numa.client.core.internal.Activator + + com.redhat.thermostat.numa.client.core, + com.redhat.thermostat.numa.client.locale + + + com.redhat.thermostat.numa.client.core.internal + + + <_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-client-core + ${project.version} + + + com.redhat.thermostat + thermostat-common-test + ${project.version} + test + + + com.redhat.thermostat + thermostat-numa-common + ${project.version} + + + diff -r ce04776b8b81 -r 8a6697503832 numa/client-core/src/main/java/com/redhat/thermostat/numa/client/core/NumaInformationService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-core/src/main/java/com/redhat/thermostat/numa/client/core/NumaInformationService.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,78 @@ +/* + * 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.numa.client.core; + +import com.redhat.thermostat.client.core.Filter; +import com.redhat.thermostat.client.core.InformationService; +import com.redhat.thermostat.client.core.NameMatchingRefFilter; +import com.redhat.thermostat.client.core.controllers.InformationServiceController; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.numa.client.core.internal.NumaController; +import com.redhat.thermostat.numa.common.NumaDAO; + +public class NumaInformationService implements InformationService { + + private static final int ORDER = ORDER_MEMORY_GROUP; + private static final Filter FILTER = new NameMatchingRefFilter<>(); + + private ApplicationService appSvc; + private NumaDAO numaDAO; + private NumaViewProvider numaViewProvider; + + public NumaInformationService(ApplicationService appSvc, NumaDAO numaDAO, NumaViewProvider numaViewProvider) { + this.appSvc = appSvc; + this.numaDAO = numaDAO; + this.numaViewProvider = numaViewProvider; + } + + @Override + public Filter getFilter() { + return FILTER; + } + + @Override + public InformationServiceController getInformationServiceController(HostRef ref) { + return new NumaController(appSvc, numaDAO, ref, numaViewProvider); + } + + @Override + public int getOrderValue() { + return ORDER; + } + +} diff -r ce04776b8b81 -r 8a6697503832 numa/client-core/src/main/java/com/redhat/thermostat/numa/client/core/NumaView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-core/src/main/java/com/redhat/thermostat/numa/client/core/NumaView.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,69 @@ +/* + * 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.numa.client.core; + +import java.util.List; + +import com.redhat.thermostat.client.core.views.BasicView; +import com.redhat.thermostat.client.core.views.UIComponent; +import com.redhat.thermostat.storage.model.DiscreteTimeData; + +public abstract class NumaView extends BasicView implements UIComponent { + + public interface GraphVisibilityChangeListener { + public void show(String tag); + + public void hide(String tag); + } + + public abstract void addNumaChart(String tag, String humanReadableName); + + public abstract void removeNumaChart(String tag); + + public abstract void showNumaChart(String tag); + + public abstract void hideNumaChart(String tag); + + public abstract void addNumaData(String tag, List> data); + + public abstract void clearNumaData(String tag); + + public abstract void addGraphVisibilityListener(GraphVisibilityChangeListener listener); + + public abstract void removeGraphVisibilityListener(GraphVisibilityChangeListener listener); + +} diff -r ce04776b8b81 -r 8a6697503832 numa/client-core/src/main/java/com/redhat/thermostat/numa/client/core/NumaViewProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-core/src/main/java/com/redhat/thermostat/numa/client/core/NumaViewProvider.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,46 @@ +/* +// * 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.numa.client.core; + +import com.redhat.thermostat.client.core.views.ViewProvider; + +public interface NumaViewProvider extends ViewProvider { + + @Override + public NumaView createView(); + +} diff -r ce04776b8b81 -r 8a6697503832 numa/client-core/src/main/java/com/redhat/thermostat/numa/client/core/internal/Activator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-core/src/main/java/com/redhat/thermostat/numa/client/core/internal/Activator.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,102 @@ +/* + * 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.numa.client.core.internal; + +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Map; +import java.util.Objects; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; + +import com.redhat.thermostat.client.core.InformationService; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.Constants; +import com.redhat.thermostat.common.MultipleServiceTracker; +import com.redhat.thermostat.common.MultipleServiceTracker.Action; +import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.numa.client.core.NumaInformationService; +import com.redhat.thermostat.numa.client.core.NumaViewProvider; +import com.redhat.thermostat.numa.common.NumaDAO; + +public class Activator implements BundleActivator { + + private MultipleServiceTracker tracker; + private ServiceRegistration reg; + + @Override + public void start(final BundleContext context) throws Exception { + Class[] deps = new Class[] { + NumaDAO.class, + ApplicationService.class, + NumaViewProvider.class + }; + + tracker = new MultipleServiceTracker(context, deps, new Action() { + + @Override + public void dependenciesAvailable(Map services) { + NumaDAO numaDAO = (NumaDAO) services.get(NumaDAO.class.getName()); + Objects.requireNonNull(numaDAO); + ApplicationService appSvc = (ApplicationService) services.get(ApplicationService.class.getName()); + Objects.requireNonNull(appSvc); + NumaViewProvider numaViewProvider = (NumaViewProvider) services.get(NumaViewProvider.class.getName()); + Objects.requireNonNull(numaViewProvider); + NumaInformationService service = new NumaInformationService(appSvc, numaDAO, numaViewProvider); + Dictionary properties = new Hashtable<>(); + properties.put(Constants.GENERIC_SERVICE_CLASSNAME, HostRef.class.getName()); + reg = context.registerService(InformationService.class.getName(), service, properties); + } + + @Override + public void dependenciesUnavailable() { + reg.unregister(); + } + + }); + tracker.open(); + } + + @Override + public void stop(BundleContext context) throws Exception { + tracker.close(); + } + +} + diff -r ce04776b8b81 -r 8a6697503832 numa/client-core/src/main/java/com/redhat/thermostat/numa/client/core/internal/NumaController.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-core/src/main/java/com/redhat/thermostat/numa/client/core/internal/NumaController.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,170 @@ +/* + * 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.numa.client.core.internal; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import com.redhat.thermostat.client.core.controllers.InformationServiceController; +import com.redhat.thermostat.client.core.views.BasicView.Action; +import com.redhat.thermostat.client.core.views.UIComponent; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.Timer.SchedulingType; +import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.common.locale.Translate; +import com.redhat.thermostat.numa.client.core.NumaView; +import com.redhat.thermostat.numa.client.core.NumaView.GraphVisibilityChangeListener; +import com.redhat.thermostat.numa.client.core.NumaViewProvider; +import com.redhat.thermostat.numa.client.locale.LocaleResources; +import com.redhat.thermostat.numa.common.NumaDAO; +import com.redhat.thermostat.numa.common.NumaStat; +import com.redhat.thermostat.storage.model.DiscreteTimeData; + +public class NumaController implements InformationServiceController { + + private static final Translate translator = LocaleResources.createLocalizer(); + + private final NumaView view; + + private final NumaDAO numaDAO; + private final HostRef ref; + + private final Timer backgroundUpdateTimer; + private final GraphVisibilityChangeListener listener = new ShowHideGraph(); + + private long lastSeenTimeStamp = Long.MIN_VALUE; + + private int numberOfNumaNodes; + + public NumaController(ApplicationService appSvc, NumaDAO numaDAO, final HostRef ref, NumaViewProvider provider) { + this.ref = ref; + this.numaDAO = numaDAO; + + numberOfNumaNodes = numaDAO.getNumberOfNumaNodes(ref); + + view = provider.createView(); + + for (int i = 0; i < numberOfNumaNodes; i++) { + view.addNumaChart("node" + i, translator.localize(LocaleResources.NUMA_NODE, String.valueOf(i))); + } + view.addGraphVisibilityListener(listener); + view.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + switch (actionEvent.getActionId()) { + case HIDDEN: + stopBackgroundUpdates(); + break; + case VISIBLE: + startBackgroundUpdates(); + break; + default: + assert false; // Cannot happen: null is caught in ActionEvent constructor, everything else by javac. + } + } + }); + + backgroundUpdateTimer = appSvc.getTimerFactory().createTimer(); + backgroundUpdateTimer.setAction(new Runnable() { + @Override + public void run() { + doNumaChartUpdate(); + } + }); + backgroundUpdateTimer.setSchedulingType(SchedulingType.FIXED_RATE); + backgroundUpdateTimer.setTimeUnit(TimeUnit.SECONDS); + backgroundUpdateTimer.setInitialDelay(0); + backgroundUpdateTimer.setDelay(5); + } + + private void startBackgroundUpdates() { + for (int i = 0; i < numberOfNumaNodes; i++) { + view.showNumaChart("node" + i); + } + + backgroundUpdateTimer.start(); + } + + private void stopBackgroundUpdates() { + backgroundUpdateTimer.stop(); + for (int i = 0; i < numberOfNumaNodes; i++) { + view.hideNumaChart("node" + i); + } + } + + public UIComponent getView() { + return view; + } + + private void doNumaChartUpdate() { + List stats = numaDAO.getLatestNumaStats(ref, lastSeenTimeStamp); + for (int i = 0; i < numberOfNumaNodes; i++) { + List> numaHitRatio = new LinkedList<>(); + + for (NumaStat stat : stats) { + long timeStamp = stat.getTimeStamp(); + long numaHitVal = stat.getNodeStats()[i].getNumaHit(); + long numaMissVal = stat.getNodeStats()[i].getNumaMiss(); + double hitRatio = 100 * numaHitVal / (numaHitVal + numaMissVal); + numaHitRatio.add(new DiscreteTimeData(timeStamp, hitRatio)); + lastSeenTimeStamp = Math.max(lastSeenTimeStamp, stat.getTimeStamp()); + } + + view.addNumaData("node" + i, numaHitRatio); + } + } + + private class ShowHideGraph implements GraphVisibilityChangeListener { + @Override + public void show(String tag) { + view.showNumaChart(tag); + } + @Override + public void hide(String tag) { + view.hideNumaChart(tag); + } + } + + @Override + public String getLocalizedName() { + return translator.localize(LocaleResources.NUMA_TAB); + } +} diff -r ce04776b8b81 -r 8a6697503832 numa/client-core/src/main/java/com/redhat/thermostat/numa/client/locale/LocaleResources.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-core/src/main/java/com/redhat/thermostat/numa/client/locale/LocaleResources.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,52 @@ +/* + * 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.numa.client.locale; + +import com.redhat.thermostat.common.locale.Translate; + +public enum LocaleResources { + NUMA_TAB, + NUMA_NODE, NUMA_SECTION_OVERVIEW, NUMA_CHART_TITLE, NUMA_CHART_TIME_LABEL, NUMA_CHART_NUM_HITS_LABEL, + ; + + static final String RESOURCE_BUNDLE = + "com.redhat.thermostat.numa.client.locale.strings"; + + public static Translate createLocalizer() { + return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class); + } +} diff -r ce04776b8b81 -r 8a6697503832 numa/client-core/src/main/resources/com/redhat/thermostat/numa/client/locale/strings.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-core/src/main/resources/com/redhat/thermostat/numa/client/locale/strings.properties Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,6 @@ +NUMA_TAB = NUMA +NUMA_NODE = Node {0} +NUMA_SECTION_OVERVIEW = NUMA +NUMA_CHART_TITLE = NUMA +NUMA_CHART_TIME_LABEL = Time +NUMA_CHART_NUM_HITS_LABEL = Number of hits diff -r ce04776b8b81 -r 8a6697503832 numa/client-core/src/test/java/com/redhat/thermostat/numa/client/core/NumaInformationServiceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-core/src/test/java/com/redhat/thermostat/numa/client/core/NumaInformationServiceTest.java Tue Jan 22 16:14:48 2013 +0100 @@ -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.numa.client.core; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.Ordered; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.TimerFactory; +import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.numa.client.core.internal.NumaController; +import com.redhat.thermostat.numa.common.NumaDAO; + +import static org.mockito.Mockito.*; + +public class NumaInformationServiceTest { + + @Test + public void test() { + ApplicationService appSvc = mock(ApplicationService.class); + TimerFactory timerFactory = mock(TimerFactory.class); + Timer timer = mock(Timer.class); + when(timerFactory.createTimer()).thenReturn(timer); + when(appSvc.getTimerFactory()).thenReturn(timerFactory); + NumaDAO numaDAO = mock(NumaDAO.class); + NumaViewProvider numaViewProvider = mock(NumaViewProvider.class); + NumaView view = mock(NumaView.class); + when(numaViewProvider.createView()).thenReturn(view); + + NumaInformationService numaInfoService = new NumaInformationService(appSvc, numaDAO, numaViewProvider); + + int order = numaInfoService.getOrderValue(); + assertEquals(Ordered.ORDER_MEMORY_GROUP, order); + HostRef ref = mock(HostRef.class); + assertTrue(numaInfoService.getInformationServiceController(ref) instanceof NumaController); + assertNotNull(numaInfoService.getFilter()); + } + +} diff -r ce04776b8b81 -r 8a6697503832 numa/client-core/src/test/java/com/redhat/thermostat/numa/client/core/internal/ActivatorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-core/src/test/java/com/redhat/thermostat/numa/client/core/internal/ActivatorTest.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,94 @@ +/* + * 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.numa.client.core.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import org.junit.Test; + +import com.redhat.thermostat.client.core.InformationService; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.numa.client.core.NumaInformationService; +import com.redhat.thermostat.numa.client.core.NumaViewProvider; +import com.redhat.thermostat.numa.common.NumaDAO; +import com.redhat.thermostat.test.StubBundleContext; + +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()); + assertNotSame(1, context.getServiceListeners().size()); + + activator.stop(context); + + assertEquals(0, context.getServiceListeners().size()); + } + + @Test + public void verifyActivatorRegistersServices() throws Exception { + StubBundleContext context = new StubBundleContext(); + NumaViewProvider numaViewProvider = mock(NumaViewProvider.class); + NumaDAO memoryStatDAO = mock(NumaDAO.class); + ApplicationService appSvc = mock(ApplicationService.class); + + context.registerService(NumaViewProvider.class, numaViewProvider, null); + context.registerService(NumaDAO.class, memoryStatDAO, null); + context.registerService(ApplicationService.class, appSvc, null); + + Activator activator = new Activator(); + + activator.start(context); + + assertTrue(context.isServiceRegistered(InformationService.class.getName(), NumaInformationService.class)); + + activator.stop(context); + + assertEquals(0, context.getServiceListeners().size()); + assertEquals(3, context.getAllServices().size()); + } + +} diff -r ce04776b8b81 -r 8a6697503832 numa/client-core/src/test/java/com/redhat/thermostat/numa/client/core/internal/NumaControllerTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-core/src/test/java/com/redhat/thermostat/numa/client/core/internal/NumaControllerTest.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,237 @@ +/* + * 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.numa.client.core.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.TimeUnit; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.Timer.SchedulingType; +import com.redhat.thermostat.common.TimerFactory; +import com.redhat.thermostat.common.dao.HostRef; +import com.redhat.thermostat.numa.client.core.NumaView; +import com.redhat.thermostat.numa.client.core.NumaView.GraphVisibilityChangeListener; +import com.redhat.thermostat.numa.client.core.NumaViewProvider; +import com.redhat.thermostat.numa.common.NumaDAO; +import com.redhat.thermostat.numa.common.NumaNodeStat; +import com.redhat.thermostat.numa.common.NumaStat; +import com.redhat.thermostat.storage.model.DiscreteTimeData; + +public class NumaControllerTest { + + private NumaController numaController; + private Timer timer; + private NumaView view; + private ArgumentCaptor graphVisibilityListener; + @SuppressWarnings("rawtypes") + private ArgumentCaptor actionListener; + private ArgumentCaptor timerAction; + + @SuppressWarnings("unchecked") + @Before + public void setUp() { + ApplicationService appSvc = mock(ApplicationService.class); + TimerFactory timerFactory = mock(TimerFactory.class); + timer = mock(Timer.class); + timerAction = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(timer).setAction(timerAction.capture()); + when(timerFactory.createTimer()).thenReturn(timer); + when(appSvc.getTimerFactory()).thenReturn(timerFactory); + HostRef hostRef = new HostRef("fluff", "boo"); + NumaDAO numaDAO = mock(NumaDAO.class); + + List stats = createTestData(); + when(numaDAO.getLatestNumaStats(eq(hostRef), anyLong())).thenReturn(stats); + when(numaDAO.getNumberOfNumaNodes(hostRef)).thenReturn(3); + NumaViewProvider numaViewProvider = mock(NumaViewProvider.class); + view = mock(NumaView.class); + graphVisibilityListener = ArgumentCaptor.forClass(GraphVisibilityChangeListener.class); + actionListener = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(view).addGraphVisibilityListener(graphVisibilityListener.capture()); + doNothing().when(view).addActionListener(actionListener.capture()); + when(numaViewProvider.createView()).thenReturn(view); + numaController = new NumaController(appSvc, numaDAO, hostRef, numaViewProvider); + } + + private List createTestData() { + NumaNodeStat nodeStat11 = new NumaNodeStat(); + nodeStat11.setNumaHit(100); + nodeStat11.setNumaMiss(0); + NumaNodeStat nodeStat12 = new NumaNodeStat(); + nodeStat12.setNumaHit(50); + nodeStat12.setNumaMiss(50); + NumaNodeStat nodeStat13 = new NumaNodeStat(); + nodeStat13.setNumaHit(70); + nodeStat13.setNumaMiss(30); + NumaStat stat1 = new NumaStat(); + stat1.setAgentId("fluff"); + stat1.setTimeStamp(123); + stat1.setNodeStats(new NumaNodeStat[] {nodeStat11, nodeStat12, nodeStat13 }); + NumaNodeStat nodeStat21 = new NumaNodeStat(); + nodeStat21.setNumaHit(90); + nodeStat21.setNumaMiss(10); + NumaNodeStat nodeStat22 = new NumaNodeStat(); + nodeStat22.setNumaHit(60); + nodeStat22.setNumaMiss(40); + NumaNodeStat nodeStat23 = new NumaNodeStat(); + nodeStat23.setNumaHit(80); + nodeStat23.setNumaMiss(20); + NumaStat stat2 = new NumaStat(); + stat2.setAgentId("fluff"); + stat2.setTimeStamp(234); + stat2.setNodeStats(new NumaNodeStat[] {nodeStat21, nodeStat22, nodeStat23 }); + List stats = Arrays.asList(stat1, stat2); + return stats; + } + + @After + public void tearDown() { + timer = null; + graphVisibilityListener = null; + view = null; + numaController = null; + } + + @Test + public void verifyTimerSettings() { + verify(timer).setAction(any(Runnable.class)); + verify(timer).setSchedulingType(SchedulingType.FIXED_RATE); + verify(timer).setTimeUnit(TimeUnit.SECONDS); + verify(timer).setInitialDelay(0); + verify(timer).setDelay(5); + verifyNoMoreInteractions(timer); + } + + @Test + public void verifyNumCharts() { + verify(view).addNumaChart(eq("node0"), anyString()); + verify(view).addNumaChart(eq("node1"), anyString()); + verify(view).addNumaChart(eq("node2"), anyString()); + } + + @Test + public void verifyGraphVisibility() { + graphVisibilityListener.getValue().show("node0"); + verify(view).showNumaChart("node0"); + graphVisibilityListener.getValue().hide("node1"); + verify(view).hideNumaChart("node1"); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void verifyViewActions() { + actionListener.getValue().actionPerformed(new ActionEvent(view, NumaView.Action.VISIBLE)); + verify(view).showNumaChart("node0"); + verify(view).showNumaChart("node1"); + verify(view).showNumaChart("node2"); + verify(timer).start(); + + actionListener.getValue().actionPerformed(new ActionEvent(view, NumaView.Action.HIDDEN)); + verify(view).hideNumaChart("node0"); + verify(view).hideNumaChart("node1"); + verify(view).hideNumaChart("node2"); + verify(timer).stop(); + + // Can't test the default branch. + } + + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void verifyTimerAction() { + timerAction.getValue().run(); + ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(List.class); + verify(view).addNumaData(eq("node0"), dataCaptor.capture()); + verify(view).addNumaData(eq("node1"), dataCaptor.capture()); + verify(view).addNumaData(eq("node2"), dataCaptor.capture()); + + List list1 = dataCaptor.getAllValues().get(0); + DiscreteTimeData data11 = (DiscreteTimeData) list1.get(0); + assertEquals(100.0, data11.getData(), 0.0); + DiscreteTimeData data12 = (DiscreteTimeData) list1.get(1); + assertEquals(90., data12.getData(), 0.0); + + List list2 = dataCaptor.getAllValues().get(1); + DiscreteTimeData data21 = (DiscreteTimeData) list2.get(0); + assertEquals(50.0, data21.getData(), 0.0); + DiscreteTimeData data22 = (DiscreteTimeData) list2.get(1); + assertEquals(60.0, data22.getData(), 0.0); + + List list3 = dataCaptor.getAllValues().get(2); + DiscreteTimeData data31 = (DiscreteTimeData) list3.get(0); + assertEquals(70.0, data31.getData(), 0.0); + DiscreteTimeData data32 = (DiscreteTimeData) list3.get(1); + assertEquals(80.0, data32.getData(), 0.0); + } + + @Test + public void testView() { + assertSame(view, numaController.getView()); + } + + @Test + public void testLocalizedName() { + Locale defaultLocale = Locale.getDefault(); + try { + Locale.setDefault(Locale.US); + assertEquals("NUMA", numaController.getLocalizedName()); + } finally { + Locale.setDefault(defaultLocale); + } + } +} diff -r ce04776b8b81 -r 8a6697503832 numa/client-core/src/test/java/com/redhat/thermostat/numa/client/locale/LocaleResourcesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-core/src/test/java/com/redhat/thermostat/numa/client/locale/LocaleResourcesTest.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,54 @@ +/* + * 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.numa.client.locale; + +import com.redhat.thermostat.numa.client.locale.LocaleResources; +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 ce04776b8b81 -r 8a6697503832 numa/client-swing/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-swing/pom.xml Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,87 @@ + + + 4.0.0 + + thermostat-numa + com.redhat.thermostat + 0.5.0-SNAPSHOT + + thermostat-numa-client-swing + bundle + Thermostat NUMA Swing Client plugin + + + + org.apache.felix + maven-bundle-plugin + true + + + com.redhat.thermostat.numa.client.swing.internal + com.redhat.thermostat.numa.client.swing.internal.Activator + Red Hat, Inc. + com.redhat.thermostat.numa.client.swing + + <_nouses>true + + + + + + + + junit + junit + test + + + org.mockito + mockito-core + test + + + org.easytesting + fest-swing + test + + + net.java.openjdk.cacio + cacio-tta + test + + + org.osgi + org.osgi.core + provided + + + org.osgi + org.osgi.compendium + provided + + + org.jfree + jfreechart + + + com.redhat.thermostat + thermostat-common-core + ${project.version} + + + com.redhat.thermostat + thermostat-client-swing + ${project.version} + + + com.redhat.thermostat + thermostat-swing-components + ${project.version} + + + com.redhat.thermostat + thermostat-numa-client-core + ${project.version} + + + diff -r ce04776b8b81 -r 8a6697503832 numa/client-swing/src/main/java/com/redhat/thermostat/numa/client/swing/internal/Activator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-swing/src/main/java/com/redhat/thermostat/numa/client/swing/internal/Activator.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,62 @@ +/* + * 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.numa.client.swing.internal; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; + +import com.redhat.thermostat.numa.client.core.NumaViewProvider; + +public class Activator implements BundleActivator { + + private ServiceRegistration serviceReg; + + @Override + public void start(final BundleContext context) throws Exception { + NumaViewProvider viewProvider = new SwingNumaViewProvider(); + // Unregistered on Activator.stop + serviceReg = context.registerService(NumaViewProvider.class.getName(), viewProvider, null); + } + + @Override + public void stop(BundleContext context) throws Exception { + serviceReg.unregister(); + } + +} + diff -r ce04776b8b81 -r 8a6697503832 numa/client-swing/src/main/java/com/redhat/thermostat/numa/client/swing/internal/NumaPanel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-swing/src/main/java/com/redhat/thermostat/numa/client/swing/internal/NumaPanel.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,332 @@ +/* + * 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.numa.client.swing.internal; + +import java.awt.Color; +import java.awt.Component; +import java.awt.FlowLayout; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.swing.GroupLayout; +import javax.swing.GroupLayout.Alignment; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.LayoutStyle.ComponentPlacement; +import javax.swing.SwingUtilities; + +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.axis.NumberTickUnit; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.data.RangeType; +import org.jfree.data.time.FixedMillisecond; +import org.jfree.data.time.RegularTimePeriod; +import org.jfree.data.time.TimeSeries; +import org.jfree.data.time.TimeSeriesCollection; + +import com.redhat.thermostat.client.swing.ComponentVisibleListener; +import com.redhat.thermostat.client.swing.SwingComponent; +import com.redhat.thermostat.client.swing.components.RecentTimeSeriesChartPanel; +import com.redhat.thermostat.client.swing.components.SectionHeader; +import com.redhat.thermostat.client.ui.ChartColors; +import com.redhat.thermostat.client.ui.RecentTimeSeriesChartController; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.locale.Translate; +import com.redhat.thermostat.numa.client.core.NumaView; +import com.redhat.thermostat.numa.client.locale.LocaleResources; +import com.redhat.thermostat.storage.model.DiscreteTimeData; +import com.redhat.thermostat.swing.components.experimental.WrapLayout; + +public class NumaPanel extends NumaView implements SwingComponent { + + private static final Translate translator = LocaleResources.createLocalizer(); + + private JPanel visiblePanel; + + private final NumaCheckboxListener numaCheckboxListener = new NumaCheckboxListener(); + + private final JPanel numaCheckBoxPanel = new JPanel(new WrapLayout(FlowLayout.LEADING)); + private final CopyOnWriteArrayList listeners = new CopyOnWriteArrayList<>(); + private final TimeSeriesCollection numaCollection = new TimeSeriesCollection(); + private final Map dataset = new HashMap<>(); + private final Map checkBoxes = new HashMap<>(); + private final Map colors = new HashMap<>(); + + private JFreeChart chart; + + public NumaPanel() { + super(); + initializePanel(); + + visiblePanel.addHierarchyListener(new ComponentVisibleListener() { + @Override + public void componentShown(Component component) { + notifier.fireAction(Action.VISIBLE); + } + @Override + public void componentHidden(Component component) { + notifier.fireAction(Action.HIDDEN); + } + }); + } + + @Override + public Component getUiComponent() { + return visiblePanel; + } + + @Override + public void addNumaChart(final String tag, final String humanReadableName) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + int colorIndex = colors.size(); + colors.put(tag, ChartColors.getColor(colorIndex)); + TimeSeries series = new TimeSeries(tag); + dataset.put(tag, series); + JCheckBox newCheckBox = new JCheckBox(createLabelWithLegend(humanReadableName, colors.get(tag))); + newCheckBox.setActionCommand(tag); + newCheckBox.setSelected(true); + newCheckBox.addActionListener(numaCheckboxListener); + newCheckBox.setOpaque(false); + checkBoxes.put(tag, newCheckBox); + numaCheckBoxPanel.add(newCheckBox); + + updateColors(); + } + }); + + } + + private String createLabelWithLegend(String text, Color color) { + String hexColor = "#" + Integer.toHexString(color.getRGB() & 0x00ffffff); + return " \u2588 " + text + ""; + } + + @Override + public void removeNumaChart(final String tag) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + TimeSeries series = dataset.remove(tag); + numaCollection.removeSeries(series); + JCheckBox box = checkBoxes.remove(tag); + numaCheckBoxPanel.remove(box); + + updateColors(); + } + }); + } + + @Override + public void showNumaChart(final String tag) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + TimeSeries series = dataset.get(tag); + numaCollection.addSeries(series); + + updateColors(); + } + }); + } + + @Override + public void hideNumaChart(final String tag) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + TimeSeries series = dataset.get(tag); + numaCollection.removeSeries(series); + + updateColors(); + } + }); + } + + @Override + public void addNumaData(final String tag, List> data) { + final List> copy = new ArrayList<>(data); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + final TimeSeries series = dataset.get(tag); + for (DiscreteTimeData timeData: copy) { + RegularTimePeriod period = new FixedMillisecond(timeData.getTimeInMillis()); + if (series.getDataItem(period) == null) { + Double data = (Double) timeData.getData(); + series.add(new FixedMillisecond(timeData.getTimeInMillis()), data, false); + } + } + series.fireSeriesChanged(); + } + }); + } + + @Override + public void clearNumaData(final String tag) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + TimeSeries series = dataset.get(tag); + series.clear(); + } + }); + } + + @Override + public void addGraphVisibilityListener(GraphVisibilityChangeListener listener) { + listeners.add(listener); + } + + @Override + public void removeGraphVisibilityListener(GraphVisibilityChangeListener listener) { + listeners.remove(listener); + } + + @Override + public void addActionListener(ActionListener listener) { + notifier.addActionListener(listener); + } + + @Override + public void removeActionListener(ActionListener listener) { + notifier.removeActionListener(listener); + } + + private void initializePanel() { + visiblePanel = new JPanel(); + visiblePanel.setOpaque(false); + + chart = createNumaChart(); + + JPanel chartPanel = new RecentTimeSeriesChartPanel(new RecentTimeSeriesChartController(chart)); + chartPanel.setOpaque(false); + + JLabel lblNuma = new SectionHeader(translator.localize(LocaleResources.NUMA_SECTION_OVERVIEW)); + + numaCheckBoxPanel.setOpaque(false); + + GroupLayout groupLayout = new GroupLayout(visiblePanel); + groupLayout.setHorizontalGroup( + groupLayout.createParallelGroup(Alignment.LEADING) + .addGroup(groupLayout.createSequentialGroup() + .addContainerGap() + .addGroup(groupLayout.createParallelGroup(Alignment.LEADING) + .addComponent(chartPanel, GroupLayout.DEFAULT_SIZE, 883, Short.MAX_VALUE) + .addComponent(lblNuma) + .addComponent(numaCheckBoxPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + groupLayout.setVerticalGroup( + groupLayout.createParallelGroup(Alignment.LEADING) + .addGroup(groupLayout.createSequentialGroup() + .addContainerGap() + .addComponent(lblNuma) + .addPreferredGap(ComponentPlacement.RELATED) + .addPreferredGap(ComponentPlacement.RELATED) + .addComponent(chartPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE) + .addPreferredGap(ComponentPlacement.RELATED) + .addComponent(numaCheckBoxPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + visiblePanel.setLayout(groupLayout); + } + + private JFreeChart createNumaChart() { + JFreeChart chart = ChartFactory.createTimeSeriesChart( + translator.localize(LocaleResources.NUMA_CHART_TITLE), // Title + translator.localize(LocaleResources.NUMA_CHART_TIME_LABEL), // x-axis Label + translator.localize(LocaleResources.NUMA_CHART_NUM_HITS_LABEL), // y-axis Label + numaCollection, // Dataset + false, // Show Legend + false, // Use tooltips + false // Configure chart to generate URLs? + ); + + chart.getPlot().setBackgroundPaint( new Color(255,255,255,0) ); + chart.getPlot().setBackgroundImageAlpha(0.0f); + chart.getPlot().setOutlinePaint(new Color(0,0,0,0)); + + NumberAxis rangeAxis = (NumberAxis) chart.getXYPlot().getRangeAxis(); + rangeAxis.setAutoRangeMinimumSize(100); + rangeAxis.setAutoRangeIncludesZero(true); + rangeAxis.setRangeType(RangeType.POSITIVE); + rangeAxis.setTickUnit(new NumberTickUnit(10.0)); + + return chart; + } + + private void fireShowHideHandlers(boolean show, String tag) { + for (GraphVisibilityChangeListener listener: listeners) { + if (show) { + listener.show(tag); + } else { + listener.hide(tag); + } + } + } + + /** + * Adding or removing series to the series collection may change the order + * of existing items. Plus the paint for the index is now out-of-date. So + * let's walk through all the series and set the right paint for those. + */ + private void updateColors() { + XYItemRenderer itemRenderer = chart.getXYPlot().getRenderer(); + for (int i = 0; i < numaCollection.getSeriesCount(); i++) { + String tag = (String) numaCollection.getSeriesKey(i); + Color color = colors.get(tag); + itemRenderer.setSeriesPaint(i, color); + } + } + + private class NumaCheckboxListener implements java.awt.event.ActionListener { + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + JCheckBox source = (JCheckBox) e.getSource(); + fireShowHideHandlers(source.isSelected(), source.getActionCommand()); + } + + } +} diff -r ce04776b8b81 -r 8a6697503832 numa/client-swing/src/main/java/com/redhat/thermostat/numa/client/swing/internal/SwingNumaViewProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-swing/src/main/java/com/redhat/thermostat/numa/client/swing/internal/SwingNumaViewProvider.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,49 @@ +/* + * 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.numa.client.swing.internal; + +import com.redhat.thermostat.numa.client.core.NumaView; +import com.redhat.thermostat.numa.client.core.NumaViewProvider; + +public class SwingNumaViewProvider implements NumaViewProvider { + + @Override + public NumaView createView() { + return new NumaPanel(); + } + +} diff -r ce04776b8b81 -r 8a6697503832 numa/client-swing/src/test/java/com/redhat/thermostat/numa/client/swing/internal/ActivatorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-swing/src/test/java/com/redhat/thermostat/numa/client/swing/internal/ActivatorTest.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,62 @@ +/* + * 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.numa.client.swing.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.redhat.thermostat.numa.client.core.NumaViewProvider; +import com.redhat.thermostat.numa.client.swing.internal.Activator; +import com.redhat.thermostat.numa.client.swing.internal.SwingNumaViewProvider; +import com.redhat.thermostat.test.StubBundleContext; + +public class ActivatorTest { + + @Test + public void verifyStartRegistersViewProvider() throws Exception { + StubBundleContext ctx = new StubBundleContext(); + Activator activator = new Activator(); + activator.start(ctx); + assertTrue(ctx.isServiceRegistered(NumaViewProvider.class.getName(), SwingNumaViewProvider.class)); + assertEquals(1, ctx.getAllServices().size()); + activator.stop(ctx); + assertEquals(0, ctx.getAllServices().size()); + } + +} diff -r ce04776b8b81 -r 8a6697503832 numa/client-swing/src/test/java/com/redhat/thermostat/numa/client/swing/internal/NumaPanelTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/client-swing/src/test/java/com/redhat/thermostat/numa/client/swing/internal/NumaPanelTest.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,69 @@ +/* + * 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.numa.client.swing.internal; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +import java.awt.Container; + +import net.java.openjdk.cacio.ctc.junit.CacioFESTRunner; + +import org.fest.swing.fixture.Containers; +import org.fest.swing.fixture.FrameFixture; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.redhat.thermostat.client.core.views.BasicView; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; + +@RunWith(CacioFESTRunner.class) +public class NumaPanelTest { + + @Test + public void testActionListener() { + NumaPanel numaPanel = new NumaPanel(); + ActionListener listener = mock(ActionListener.class); + numaPanel.addActionListener(listener); + FrameFixture frameFixture = Containers.frameFixtureFor((Container) numaPanel.getUiComponent()); + frameFixture.show(); + verify(listener).actionPerformed(new ActionEvent(numaPanel, BasicView.Action.VISIBLE)); + frameFixture.close(); + verify(listener).actionPerformed(new ActionEvent(numaPanel, BasicView.Action.VISIBLE)); + } +} diff -r ce04776b8b81 -r 8a6697503832 numa/common/src/main/java/com/redhat/thermostat/numa/common/NodeStat.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/NodeStat.java Tue Jan 22 16:14:48 2013 +0100 @@ -0,0 +1,125 @@ +/* + * 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.numa.common; + +import com.redhat.thermostat.storage.core.Persist; +import com.redhat.thermostat.storage.model.Pojo; + +public class NodeStat implements Pojo { + + private long numaHit = -1; + private long numaMiss = -1; + private long numaForeign = -1; + private long interleaveHit = -1; + private long localNode = -1; + private long otherNode = -1; + private int node = -1; + + @Persist + public long getNumaHit() { + return numaHit; + } + + @Persist + public void setNumaHit(long numaHit) { + this.numaHit = numaHit; + } + + @Persist + public long getNumaMiss() { + return numaMiss; + } + + @Persist + public void setNumaMiss(long numaMiss) { + this.numaMiss = numaMiss; + } + + @Persist + public long getNumaForeign() { + return numaForeign; + } + + @Persist + public void setNumaForeign(long numaForeign) { + this.numaForeign = numaForeign; + } + + @Persist + public long getInterleaveHit() { + return interleaveHit; + } + + @Persist + public void setInterleaveHit(long interleaveHit) { + this.interleaveHit = interleaveHit; + } + + @Persist + public long getLocalNode() { + return localNode; + } + + @Persist + public void setLocalNode(long localNode) { + this.localNode = localNode; + } + + @Persist + public long getOtherNode() { + return otherNode; + } + + @Persist + public void setOtherNode(long otherNode) { + this.otherNode = otherNode; + } + + @Persist + public int getNode() { + return node; + } + + @Persist + public void setNode(int node) { + this.node = node; + } + + public String toString() { + return "NumaStat: node: " + node + ", numaHit: " + numaHit + ", numaMiss: " + numaMiss + ", numaForeign: " + numaForeign + ", interleaveHit: " + interleaveHit + ", localNode: " + localNode + ", otherNode: " + otherNode; + } +} diff -r ce04776b8b81 -r 8a6697503832 numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaDAO.java --- a/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaDAO.java Fri Jan 18 18:43:12 2013 +0100 +++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaDAO.java Tue Jan 22 16:14:48 2013 +0100 @@ -36,6 +36,9 @@ package com.redhat.thermostat.numa.common; +import java.util.List; + +import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Key; @@ -45,5 +48,14 @@ static final Category numaStatCategory = new Category<>("numa-stat", NumaStat.class, Key.AGENT_ID, Key.TIMESTAMP, nodeStats); + static final Key hostNumNumaNodes = new Key<>("hostNumNumaNodes", false); + + static final Category numaHostCategory = new Category<>("numa-host-info", NumaHostInfo.class, Key.AGENT_ID, hostNumNumaNodes); + + void putNumberOfNumaNodes(int numNodes); + int getNumberOfNumaNodes(HostRef ref); + void putNumaStat(NumaStat stat); + + List getLatestNumaStats(HostRef ref, long lastSeenTimeStamp); } diff -r ce04776b8b81 -r 8a6697503832 numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaHostInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaHostInfo.java Tue Jan 22 16:14:48 2013 +0100 @@ -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.numa.common; + +import com.redhat.thermostat.storage.model.BasePojo; + +public class NumaHostInfo extends BasePojo { + + private int numNumaNodes; + + public void setNumNumaNodes(int numNumaNodes) { + this.numNumaNodes = numNumaNodes; + } + + public int getNumNumaNodes() { + return numNumaNodes; + } + +} diff -r ce04776b8b81 -r 8a6697503832 numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaStat.java --- a/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaStat.java Fri Jan 18 18:43:12 2013 +0100 +++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaStat.java Tue Jan 22 16:14:48 2013 +0100 @@ -40,13 +40,15 @@ import com.redhat.thermostat.storage.core.Entity; import com.redhat.thermostat.storage.core.Persist; import com.redhat.thermostat.storage.model.BasePojo; +import com.redhat.thermostat.storage.model.TimeStampedPojo; @Entity -public class NumaStat extends BasePojo { +public class NumaStat extends BasePojo implements TimeStampedPojo{ private long timeStamp = -1; private NumaNodeStat[] nodeStats = new NumaNodeStat[0]; + @Override @Persist public long getTimeStamp() { return timeStamp; diff -r ce04776b8b81 -r 8a6697503832 numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/Activator.java --- a/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/Activator.java Fri Jan 18 18:43:12 2013 +0100 +++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/Activator.java Tue Jan 22 16:14:48 2013 +0100 @@ -56,14 +56,13 @@ @Override public Object addingService(ServiceReference reference) { Storage storage = (Storage) context.getService(reference); - NumaDAO memoryStatDao = new NumaDAOImpl(storage); - reg = context.registerService(NumaDAO.class.getName(), memoryStatDao, null); + NumaDAO numaDao = new NumaDAOImpl(storage); + reg = context.registerService(NumaDAO.class.getName(), numaDao, null); return super.addingService(reference); } @Override - public void removedService(ServiceReference reference, - Object service) { + public void removedService(ServiceReference reference, Object service) { reg.unregister(); super.removedService(reference, service); } diff -r ce04776b8b81 -r 8a6697503832 numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java --- a/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java Fri Jan 18 18:43:12 2013 +0100 +++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImpl.java Tue Jan 22 16:14:48 2013 +0100 @@ -36,18 +36,32 @@ package com.redhat.thermostat.numa.common.internal; +import java.util.List; + +import com.redhat.thermostat.common.dao.HostLatestPojoListGetter; +import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.numa.common.NumaDAO; +import com.redhat.thermostat.numa.common.NumaHostInfo; import com.redhat.thermostat.numa.common.NumaStat; +import com.redhat.thermostat.storage.core.Cursor; +import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.Put; +import com.redhat.thermostat.storage.core.Query; +import com.redhat.thermostat.storage.core.Query.Criteria; +import com.redhat.thermostat.storage.core.Replace; import com.redhat.thermostat.storage.core.Storage; public class NumaDAOImpl implements NumaDAO { private final Storage storage; + private final HostLatestPojoListGetter getter; + NumaDAOImpl(Storage storage) { this.storage = storage; storage.registerCategory(numaStatCategory); + storage.registerCategory(numaHostCategory); + this.getter = new HostLatestPojoListGetter<>(storage, numaStatCategory); } @Override @@ -56,4 +70,31 @@ add.setPojo(stat); add.apply(); } + + @Override + public List getLatestNumaStats(HostRef ref, long lastTimeStamp) { + return getter.getLatest(ref, lastTimeStamp); + } + + @Override + public void putNumberOfNumaNodes(int numNodes) { + Replace replace = storage.createReplace(numaHostCategory); + NumaHostInfo numaHostInfo = new NumaHostInfo(); + numaHostInfo.setNumNumaNodes(numNodes); + replace.setPojo(numaHostInfo); + replace.apply(); + } + + @Override + public int getNumberOfNumaNodes(HostRef ref) { + Query query = storage.createQuery(numaHostCategory); + query.where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgentId()); + query.limit(1); + Cursor numaHostInfo = query.execute(); + if (numaHostInfo.hasNext()) { + return numaHostInfo.next().getNumNumaNodes(); + } else { + return 0; + } + } } diff -r ce04776b8b81 -r 8a6697503832 numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaHostInfoTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaHostInfoTest.java Tue Jan 22 16:14:48 2013 +0100 @@ -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.numa.common; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class NumaHostInfoTest { + + @Test + public void testGetterSetter() { + NumaHostInfo numaHostInfo = new NumaHostInfo(); + numaHostInfo.setNumNumaNodes(42); + assertEquals(42, numaHostInfo.getNumNumaNodes()); + } +} diff -r ce04776b8b81 -r 8a6697503832 numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java --- a/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java Fri Jan 18 18:43:12 2013 +0100 +++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java Tue Jan 22 16:14:48 2013 +0100 @@ -95,6 +95,7 @@ numaDAO.putNumaStat(numaStat); verify(storage).registerCategory(NumaDAO.numaStatCategory); + verify(storage).registerCategory(NumaDAO.numaHostCategory); verify(storage).createAdd(NumaDAO.numaStatCategory); verifyNoMoreInteractions(storage); verify(add).setPojo(numaStat); diff -r ce04776b8b81 -r 8a6697503832 numa/pom.xml --- a/numa/pom.xml Fri Jan 18 18:43:12 2013 +0100 +++ b/numa/pom.xml Tue Jan 22 16:14:48 2013 +0100 @@ -53,6 +53,8 @@ agent common + client-core + client-swing