Mercurial > hg > release > thermostat-1.2
changeset 1562:dee75542747f
Add gui bits for the profiler
Reviewed-by: neugens
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2014-November/011622.html
line wrap: on
line diff
--- a/vm-profiler/client-core/pom.xml Fri Nov 21 11:02:34 2014 -0500 +++ b/vm-profiler/client-core/pom.xml Mon Nov 24 13:12:39 2014 -0500 @@ -75,7 +75,7 @@ <Bundle-Activator>com.redhat.thermostat.vm.profiler.client.core.internal.Activator</Bundle-Activator> <Export-Package> com.redhat.thermostat.vm.profiler.client.core, - com.redhat.thermostat.vm.profiler.client.locale + com.redhat.thermostat.vm.profiler.client.locale, </Export-Package> <Private-Package> com.redhat.thermostat.vm.profiler.client.core.internal
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-core/src/main/java/com/redhat/thermostat/vm/profiler/client/core/ProfilingResultParser.java Mon Nov 24 13:12:39 2014 -0500 @@ -0,0 +1,80 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.profiler.client.core; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.common.utils.LoggingUtils; + +public class ProfilingResultParser { + + private static final Logger logger = LoggingUtils.getLogger(ProfilingResultParser.class); + + public class ProfilingResult { + /** Method Name -> Time (ns) */ + public final Map<String, Long> time; + public ProfilingResult(Map<String, Long> data) { + this.time = Collections.unmodifiableMap(data); + } + } + + public ProfilingResult parse(InputStream in) { + Map<String, Long> result = new HashMap<String, Long>(); + + try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { + String line; + while ((line = reader.readLine()) != null) { + String[] parts = line.split("\\s+"); + long time = Long.valueOf(parts[0]); + String name = parts[1]; + result.put(name, time); + } + } catch (IOException e) { + logger.log(Level.WARNING, "Unable to parse profiling data: ", e); + } + return new ProfilingResult(result); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-core/src/test/java/com/redhat/thermostat/vm/profiler/client/core/ProfilingResultParserTest.java Mon Nov 24 13:12:39 2014 -0500 @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.profiler.client.core; + +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import org.junit.Test; + +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser.ProfilingResult; + +public class ProfilingResultParserTest { + + @Test + public void parsesCorrectly() throws Exception { + String data = "1 foo\n2 bar"; + ByteArrayInputStream in = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)); + ProfilingResultParser parser = new ProfilingResultParser(); + ProfilingResult result = parser.parse(in); + Map<String, Long> times = result.time; + assertEquals(1, (long) times.get("foo")); + assertEquals(2, (long) times.get("bar")); + } +}
--- a/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/Activator.java Fri Nov 21 11:02:34 2014 -0500 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/Activator.java Mon Nov 24 13:12:39 2014 -0500 @@ -36,26 +36,66 @@ package com.redhat.thermostat.vm.profiler.client.swing.internal; +import java.util.Hashtable; import java.util.Map; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; +import com.redhat.thermostat.client.command.RequestQueue; +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.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; public class Activator implements BundleActivator { + private ServiceRegistration<InformationService> registration; + private MultipleServiceTracker tracker; + @Override public void start(final BundleContext context) throws Exception { - // TODO implement me + + Class<?>[] deps = new Class<?>[] { + ApplicationService.class, + AgentInfoDAO.class, + ProfileDAO.class, + RequestQueue.class, + }; + + tracker = new MultipleServiceTracker(context, deps, new MultipleServiceTracker.Action() { + @Override + public void dependenciesAvailable(Map<String, Object> services) { + ApplicationService service = (ApplicationService) services.get(ApplicationService.class.getName()); + AgentInfoDAO agentInfoDao = (AgentInfoDAO) services.get(AgentInfoDAO.class.getName()); + ProfileDAO profileDao = (ProfileDAO) services.get(ProfileDAO.class.getName()); + RequestQueue queue = (RequestQueue) services.get(RequestQueue.class.getName()); + + InformationService<VmRef> profileService = new VmProfileService(service, agentInfoDao, profileDao, queue); + + Hashtable<String,String> properties = new Hashtable<>(); + properties.put(Constants.GENERIC_SERVICE_CLASSNAME, VmRef.class.getName()); + properties.put(InformationService.KEY_SERVICE_ID, profileService.getClass().getName()); + + registration = context.registerService(InformationService.class, profileService, properties); + } + + @Override + public void dependenciesUnavailable() { + registration.unregister(); + registration = null; + } + }); + tracker.open(); } @Override public void stop(BundleContext context) throws Exception { - // TODO implement me + tracker.close(); } } -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/LocaleResources.java Mon Nov 24 13:12:39 2014 -0500 @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.profiler.client.swing.internal; + +import com.redhat.thermostat.shared.locale.Translate; + +public enum LocaleResources { + + PROFILER_TAB_NAME, + + PROFILER_HEADING, + START_PROFILING, + STOP_PROFILING, + + PROFILER_LIST_ITEM, + PROFILER_RESULTS_METHOD, + PROFILER_RESULTS_TIME, + ; + + static final String RESOURCE_BUNDLE = "com.redhat.thermostat.vm.profiler.client.swing.internal.strings"; + + public static Translate<LocaleResources> createLocalizer() { + return new Translate<>(RESOURCE_BUNDLE, LocaleResources.class); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/SwingVmProfileView.java Mon Nov 24 13:12:39 2014 -0500 @@ -0,0 +1,230 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.profiler.client.swing.internal; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.util.Date; +import java.util.List; +import java.util.Map.Entry; +import java.util.Vector; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.SwingWorker; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.table.DefaultTableModel; + +import com.redhat.thermostat.client.swing.IconResource; +import com.redhat.thermostat.client.swing.SwingComponent; +import com.redhat.thermostat.client.swing.components.ActionToggleButton; +import com.redhat.thermostat.client.swing.components.HeaderPanel; +import com.redhat.thermostat.client.swing.experimental.ComponentVisibilityNotifier; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser.ProfilingResult; + +public class SwingVmProfileView extends VmProfileView implements SwingComponent { + + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + + private static final double SPLIT_PANE_RATIO = 0.3; + + private final CopyOnWriteArrayList<ActionListener<ProfileAction>> listeners = + new CopyOnWriteArrayList<>(); + + private HeaderPanel mainContainer; + + private ActionToggleButton startStopProfilingButton; + + private DefaultListModel<Profile> listModel; + private JList<Profile> profileList; + + private DefaultTableModel tableModel; + + static class ProfileItemRenderer extends DefaultListCellRenderer { + @Override + public Component getListCellRendererComponent(JList<?> list, + Object value, int index, boolean isSelected, + boolean cellHasFocus) { + if (value instanceof Profile) { + Profile profile = (Profile) value; + value = translator + .localize(LocaleResources.PROFILER_LIST_ITEM, + profile.name, new Date(profile.timeStamp).toString()) + .getContents(); + } + return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + } + } + + public SwingVmProfileView() { + listModel = new DefaultListModel<>(); + + startStopProfilingButton = new ActionToggleButton( + IconResource.RECORD.getIcon()); + updateProfilingButtonStatus(false); + + startStopProfilingButton.addActionListener(new java.awt.event.ActionListener() { + @Override + public void actionPerformed(java.awt.event.ActionEvent e) { + if (startStopProfilingButton.isSelected()) { + updateProfilingButtonStatus(true); + fireProfileAction(ProfileAction.START_PROFILING); + } else { + updateProfilingButtonStatus(false); + fireProfileAction(ProfileAction.STOP_PROFILING); + } + } + }); + + mainContainer = new HeaderPanel(translator.localize(LocaleResources.PROFILER_HEADING)); + mainContainer.addToolBarButton(startStopProfilingButton); + new ComponentVisibilityNotifier().initialize(mainContainer, notifier); + + profileList = new JList<>(listModel); + profileList.setCellRenderer(new ProfileItemRenderer()); + profileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + profileList.addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + if (e.getValueIsAdjusting()) { + return; + } + + fireProfileAction(ProfileAction.PROFILE_SELECTED); + } + }); + JScrollPane profileListPane = new JScrollPane(profileList); + + Vector<String> columnNames = new Vector<>(); + columnNames.add(translator.localize(LocaleResources.PROFILER_RESULTS_METHOD).getContents()); + columnNames.add(translator.localize(LocaleResources.PROFILER_RESULTS_TIME, "ns").getContents()); + tableModel = new DefaultTableModel(columnNames, 0); + + JTable profileTable = new JTable(tableModel); + JScrollPane profileTablePane = new JScrollPane(profileTable); + + JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + profileListPane, profileTablePane); + splitPane.setDividerLocation(SPLIT_PANE_RATIO); + splitPane.setResizeWeight(0.5); + + mainContainer.add(splitPane, BorderLayout.CENTER); + } + + @Override + public void addProfileActionListener(ActionListener<ProfileAction> listener) { + listeners.add(listener); + } + + @Override + public void removeProfileActionlistener(ActionListener<ProfileAction> listener) { + listeners.remove(listener); + } + + private void fireProfileAction(final ProfileAction action) { + new SwingWorker<Void, Void>() { + @Override + protected Void doInBackground() throws Exception { + ActionEvent<ProfileAction> event = new ActionEvent<>(this, action); + for (ActionListener<ProfileAction> listener : listeners) { + listener.actionPerformed(event); + } + return null; + } + }.execute(); + } + + @Override + public void setCurrentlyProfiling(boolean currentlyProfiling) { + updateProfilingButtonStatus(currentlyProfiling); + } + + private void updateProfilingButtonStatus(boolean currentlyProfiling) { + if (currentlyProfiling) { + startStopProfilingButton.setText(translator.localize(LocaleResources.STOP_PROFILING).getContents()); + } else { + startStopProfilingButton.setText(translator.localize(LocaleResources.START_PROFILING).getContents()); + } + } + + @Override + public void setAvailableProfilingRuns(List<Profile> data) { + listModel.clear(); + for (Profile item : data) { + listModel.addElement(item); + } + } + + @Override + public Profile getSelectedProfile() { + if (profileList.isSelectionEmpty()) { + throw new AssertionError("Selection is empty"); + // return null; + } + return profileList.getSelectedValue(); + } + + @Override + public void setProfilingDetailData(ProfilingResult results) { + // delete all existing data + tableModel.setRowCount(0); + + for (Entry<String, Long> methodAndTime : results.time.entrySet()) { + Object[] data = new Object[] { + methodAndTime.getKey(), + methodAndTime.getValue(), + }; + tableModel.addRow(data); + } + } + + @Override + public Component getUiComponent() { + return mainContainer; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileController.java Mon Nov 24 13:12:39 2014 -0500 @@ -0,0 +1,195 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.profiler.client.swing.internal; + +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import com.redhat.thermostat.client.command.RequestQueue; +import com.redhat.thermostat.client.core.controllers.InformationServiceController; +import com.redhat.thermostat.client.core.views.BasicView; +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.Clock; +import com.redhat.thermostat.common.SystemClock; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.Timer.SchedulingType; +import com.redhat.thermostat.common.command.Request; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.shared.locale.LocalizedString; +import com.redhat.thermostat.shared.locale.Translate; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser.ProfilingResult; +import com.redhat.thermostat.vm.profiler.client.swing.internal.VmProfileView.Profile; +import com.redhat.thermostat.vm.profiler.client.swing.internal.VmProfileView.ProfileAction; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; +import com.redhat.thermostat.vm.profiler.common.ProfileInfo; +import com.redhat.thermostat.vm.profiler.common.ProfileRequest; + +public class VmProfileController implements InformationServiceController<VmRef> { + + private static final Translate<LocaleResources> translator = LocaleResources.createLocalizer(); + + private ApplicationService service; + private ProfileDAO profileDao; + private AgentInfoDAO agentInfoDao; + private RequestQueue queue; + private VmRef vm; + + private VmProfileView view; + + private Timer updater; + + private Clock clock; + + public VmProfileController(ApplicationService service, + AgentInfoDAO agentInfoDao, ProfileDAO dao, + RequestQueue queue, + VmRef vm) { + this(service, agentInfoDao, dao, queue, new SystemClock(), new SwingVmProfileView(), vm); + } + + VmProfileController(ApplicationService service, + AgentInfoDAO agentInfoDao, ProfileDAO dao, + RequestQueue queue, Clock clock, + VmProfileView view, VmRef vm) { + this.service = service; + this.agentInfoDao = agentInfoDao; + this.profileDao = dao; + this.queue = queue; + this.clock = clock; + this.view = view; + this.vm = vm; + + // TODO dispose the timer when done + updater = service.getTimerFactory().createTimer(); + updater.setSchedulingType(SchedulingType.FIXED_DELAY); + updater.setInitialDelay(0); + updater.setDelay(5); + updater.setTimeUnit(TimeUnit.SECONDS); + updater.setAction(new Runnable() { + @Override + public void run() { + updateViewWithProfiledRuns(); + } + }); + + view.addActionListener(new ActionListener<BasicView.Action>() { + @Override + public void actionPerformed(ActionEvent<Action> actionEvent) { + switch (actionEvent.getActionId()) { + case HIDDEN: + updater.stop(); + break; + case VISIBLE: + updater.start(); + break; + default: + throw new AssertionError("Unknown action event: " + actionEvent); + } + } + }); + + view.addProfileActionListener(new ActionListener<VmProfileView.ProfileAction>() { + @Override + public void actionPerformed(ActionEvent<ProfileAction> actionEvent) { + ProfileAction id = actionEvent.getActionId(); + switch (id) { + case START_PROFILING: + sendProfilingRequest(true); + break; + case STOP_PROFILING: + sendProfilingRequest(false); + break; + case PROFILE_SELECTED: + updateViewWithProfileRunData(); + break; + default: + throw new AssertionError("Unknown event: " + id); + } + } + }); + } + + private void sendProfilingRequest(boolean start) { + InetSocketAddress address = agentInfoDao.getAgentInformation(vm.getHostRef()).getRequestQueueAddress(); + String action = start ? ProfileRequest.START_PROFILING : ProfileRequest.STOP_PROFILING; + Request req = ProfileRequest.create(address, vm.getVmId(), action); + queue.putRequest(req); + } + + private void updateViewWithProfiledRuns() { + long end = clock.getRealTimeMillis(); + long start = end - TimeUnit.DAYS.toMillis(1); // FIXME hardcoded 1 day + + List<ProfileInfo> profileInfos = profileDao.getAllProfileInfo(vm, new Range<>(start, end)); + List<Profile> profiles = new ArrayList<>(); + for (ProfileInfo profileInfo : profileInfos) { + Profile profile = new Profile(profileInfo.getProfileId(), profileInfo.getTimeStamp()); + profiles.add(profile); + } + + view.setAvailableProfilingRuns(profiles); + } + + private void updateViewWithProfileRunData() { + Profile selectedProfile = view.getSelectedProfile(); + String profileId = selectedProfile.name; + InputStream in = profileDao.loadProfileDataById(vm, profileId); + ProfilingResult result = new ProfilingResultParser().parse(in); + view.setProfilingDetailData(result); + } + + @Override + public UIComponent getView() { + return view; + } + + @Override + public LocalizedString getLocalizedName() { + return translator.localize(LocaleResources.PROFILER_TAB_NAME); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileService.java Mon Nov 24 13:12:39 2014 -0500 @@ -0,0 +1,79 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.profiler.client.swing.internal; + +import com.redhat.thermostat.client.command.RequestQueue; +import com.redhat.thermostat.client.core.InformationService; +import com.redhat.thermostat.client.core.controllers.InformationServiceController; +import com.redhat.thermostat.common.AllPassFilter; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.Filter; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; + +public class VmProfileService implements InformationService<VmRef> { + + private ApplicationService service; + private AgentInfoDAO agentInfoDao; + private ProfileDAO dao; + private RequestQueue queue; + + public VmProfileService(ApplicationService service, AgentInfoDAO agentInfoDao, ProfileDAO dao, RequestQueue queue) { + this.service = service; + this.agentInfoDao = agentInfoDao; + this.dao = dao; + this.queue = queue; + } + + @Override + public int getOrderValue() { + return ORDER_CPU_GROUP + 20; + } + + @Override + public Filter<VmRef> getFilter() { + // we can't profile dead VMs, but we can still look at old profiling data. + return new AllPassFilter<>(); + } + + @Override + public InformationServiceController<VmRef> getInformationServiceController(VmRef ref) { + return new VmProfileController(service, agentInfoDao, dao, queue, ref); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/main/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileView.java Mon Nov 24 13:12:39 2014 -0500 @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.profiler.client.swing.internal; + +import java.util.List; + +import com.redhat.thermostat.client.core.views.BasicView; +import com.redhat.thermostat.client.core.views.UIComponent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser.ProfilingResult; + +public abstract class VmProfileView extends BasicView implements UIComponent { + + static class Profile { + public final String name; + public final long timeStamp; + public Profile(String name, long timeStamp) { + this.name = name; + this.timeStamp = timeStamp; + } + } + + enum ProfileAction { + START_PROFILING, + STOP_PROFILING, + + PROFILE_SELECTED, + } + + public abstract void addProfileActionListener(ActionListener<ProfileAction> listener); + + public abstract void removeProfileActionlistener(ActionListener<ProfileAction> listener); + + public abstract void setCurrentlyProfiling(boolean profiling); + + public abstract void setAvailableProfilingRuns(List<Profile> data); + + public abstract Profile getSelectedProfile(); + + public abstract void setProfilingDetailData(ProfilingResult results); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/main/resources/com/redhat/thermostat/vm/profiler/client/swing/internal/strings.properties Mon Nov 24 13:12:39 2014 -0500 @@ -0,0 +1,10 @@ +PROFILER_TAB_NAME = Profiler + +PROFILER_HEADING = JVM Profiler + +START_PROFILING = Start Profiling +STOP_PROFILING = Stop Profiling + +PROFILER_LIST_ITEM = Session @ {1} ({0}) +PROFILER_RESULTS_METHOD = Method +PROFILER_RESULTS_TIME = Cumulative Time ({0}) \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/ActivatorTest.java Mon Nov 24 13:12:39 2014 -0500 @@ -0,0 +1,77 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.profiler.client.swing.internal; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import org.junit.Test; + +import com.redhat.thermostat.client.command.RequestQueue; +import com.redhat.thermostat.client.core.InformationService; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.testutils.StubBundleContext; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; + +public class ActivatorTest { + + @Test + public void verifyActivatorRegistersGuiService() throws Exception { + StubBundleContext bundleContext = new StubBundleContext(); + + ApplicationService appService = mock(ApplicationService.class); + bundleContext.registerService(ApplicationService.class, appService, null); + + AgentInfoDAO agentInfoDao = mock(AgentInfoDAO.class); + bundleContext.registerService(AgentInfoDAO.class, agentInfoDao, null); + + ProfileDAO profielDao = mock(ProfileDAO.class); + bundleContext.registerService(ProfileDAO.class, profielDao, null); + + RequestQueue requestQueue = mock(RequestQueue.class); + bundleContext.registerService(RequestQueue.class, requestQueue, null); + + Activator activator = new Activator(); + + activator.start(bundleContext); + + assertTrue(bundleContext.isServiceRegistered(InformationService.class.getName(), VmProfileService.class)); + + activator.stop(bundleContext); + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/LocaleResourcesTest.java Mon Nov 24 13:12:39 2014 -0500 @@ -0,0 +1,53 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.profiler.client.swing.internal; + +import com.redhat.thermostat.testutils.AbstractLocaleResourcesTest; + +public class LocaleResourcesTest extends AbstractLocaleResourcesTest<LocaleResources> { + + @Override + protected Class<LocaleResources> getEnumClass() { + return LocaleResources.class; + } + + @Override + protected String getResourceBundle() { + return LocaleResources.RESOURCE_BUNDLE; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileControllerTest.java Mon Nov 24 13:12:39 2014 -0500 @@ -0,0 +1,246 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.profiler.client.swing.internal; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.client.command.RequestQueue; +import com.redhat.thermostat.client.core.views.BasicView.Action; +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.ApplicationService; +import com.redhat.thermostat.common.Clock; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.TimerFactory; +import com.redhat.thermostat.common.command.Request; +import com.redhat.thermostat.common.model.Range; +import com.redhat.thermostat.storage.core.HostRef; +import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.vm.profiler.client.core.ProfilingResultParser.ProfilingResult; +import com.redhat.thermostat.vm.profiler.client.swing.internal.VmProfileView.Profile; +import com.redhat.thermostat.vm.profiler.client.swing.internal.VmProfileView.ProfileAction; +import com.redhat.thermostat.vm.profiler.common.ProfileDAO; +import com.redhat.thermostat.vm.profiler.common.ProfileInfo; +import com.redhat.thermostat.vm.profiler.common.ProfileRequest; + +public class VmProfileControllerTest { + + private static final String AGENT_ID = "some-agent-id"; + private static final String AGENT_HOST = "foo"; + private static final int AGENT_PORT = 10; + private static final InetSocketAddress AGENT_ADDRESS = new InetSocketAddress(AGENT_HOST, AGENT_PORT); + private static final String VM_ID = "some-vm-id"; + private static final String PROFILE_ID = "some-profile-id"; + + private Timer timer; + private ApplicationService appService; + private AgentInfoDAO agentInfoDao; + private ProfileDAO profileDao; + private RequestQueue queue; + private Clock clock; + private VmProfileView view; + private VmRef vm; + + private VmProfileController controller; + private HostRef agent; + + + @Before + public void setUp() { + timer = mock(Timer.class); + + TimerFactory timerFactory = mock(TimerFactory.class); + when(timerFactory.createTimer()).thenReturn(timer); + + appService = mock(ApplicationService.class); + when(appService.getTimerFactory()).thenReturn(timerFactory); + + agentInfoDao = mock(AgentInfoDAO.class); + profileDao = mock(ProfileDAO.class); + queue = mock(RequestQueue.class); + + clock = mock(Clock.class); + view = mock(VmProfileView.class); + + agent = mock(HostRef.class); + when(agent.getAgentId()).thenReturn(AGENT_ID); + + vm = mock(VmRef.class); + when(vm.getHostRef()).thenReturn(agent); + when(vm.getVmId()).thenReturn(VM_ID); + + AgentInformation agentInfo = new AgentInformation(); + agentInfo.setConfigListenAddress(AGENT_HOST + ":" + AGENT_PORT); + when(agentInfoDao.getAgentInformation(agent)).thenReturn(agentInfo); + } + + @Test + public void timerRunsWhenVisible() throws Exception { + controller = createController(); + + verify(timer, never()).start(); + + ArgumentCaptor<ActionListener> listenerCaptor = ArgumentCaptor.forClass(ActionListener.class); + verify(view).addActionListener(listenerCaptor.capture()); + + listenerCaptor.getValue().actionPerformed(new ActionEvent<>(view, Action.VISIBLE)); + verify(timer).start(); + } + + + @Test + public void timerStopsWhenHidden() throws Exception { + controller = createController(); + + verify(timer, never()).start(); + + ArgumentCaptor<ActionListener> listenerCaptor = ArgumentCaptor.forClass(ActionListener.class); + verify(view).addActionListener(listenerCaptor.capture()); + + listenerCaptor.getValue().actionPerformed(new ActionEvent<Enum<?>>(view, Action.HIDDEN)); + verify(timer).stop(); + } + + @Test + public void timerUpdatesView() throws Exception { + final long SOME_TIMESTAMP = 1000000000; + final long PROFILE_TIMESTAMP = SOME_TIMESTAMP - 100; + + when(clock.getRealTimeMillis()).thenReturn(SOME_TIMESTAMP); + controller = createController(); + + ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(timer).setAction(runnableCaptor.capture()); + + ProfileInfo profile = new ProfileInfo(AGENT_ID, VM_ID, PROFILE_TIMESTAMP, PROFILE_ID); + + when(profileDao.getAllProfileInfo(vm, + new Range<>(SOME_TIMESTAMP - TimeUnit.DAYS.toMillis(1) , SOME_TIMESTAMP))) + .thenReturn(Arrays.asList(profile)); + + Runnable runnable = runnableCaptor.getValue(); + runnable.run(); + + ArgumentCaptor<List> listCaptor = ArgumentCaptor.forClass(List.class); + verify(view).setAvailableProfilingRuns(listCaptor.capture()); + List<Profile> resultList = listCaptor.getValue(); + assertEquals(1, resultList.size()); + assertEquals(PROFILE_TIMESTAMP, resultList.get(0).timeStamp); + } + + @Test + public void startProfilingWorks() throws Exception { + controller = createController(); + + ArgumentCaptor<ActionListener> listenerCaptor = ArgumentCaptor.forClass(ActionListener.class); + verify(view).addProfileActionListener(listenerCaptor.capture()); + + listenerCaptor.getValue().actionPerformed(new ActionEvent<>(view, ProfileAction.START_PROFILING)); + + ArgumentCaptor<Request> requestCaptor = ArgumentCaptor.forClass(Request.class); + verify(queue).putRequest(requestCaptor.capture()); + Request expectedRequest = ProfileRequest.create(AGENT_ADDRESS, VM_ID, ProfileRequest.START_PROFILING); + Request actualRequest = requestCaptor.getValue(); + assertRequestEquals(actualRequest, expectedRequest); + } + + @Test + public void stopProfilingWorks() throws Exception { + controller = createController(); + + ArgumentCaptor<ActionListener> listenerCaptor = ArgumentCaptor.forClass(ActionListener.class); + verify(view).addProfileActionListener(listenerCaptor.capture()); + + listenerCaptor.getValue().actionPerformed(new ActionEvent<>(view, ProfileAction.STOP_PROFILING)); + + ArgumentCaptor<Request> requestCaptor = ArgumentCaptor.forClass(Request.class); + verify(queue).putRequest(requestCaptor.capture()); + + Request expectedRequest = ProfileRequest.create(AGENT_ADDRESS, VM_ID, ProfileRequest.STOP_PROFILING); + Request actualRequest = requestCaptor.getValue(); + + assertRequestEquals(actualRequest, expectedRequest); + } + + private void assertRequestEquals(Request actual, Request expected) { + assertEquals(expected.getParameterNames(), actual.getParameterNames()); + assertEquals(expected.getReceiver(), actual.getReceiver()); + assertEquals(expected.getType(), actual.getType()); + } + + @Test + public void selectingAProfileShowsDetails() throws Exception { + final String PROFILE_DATA = "1 foo"; + + controller = createController(); + + ArgumentCaptor<ActionListener> listenerCaptor = ArgumentCaptor.forClass(ActionListener.class); + verify(view).addProfileActionListener(listenerCaptor.capture()); + + Profile PROFILE = new Profile(PROFILE_ID, 10); + + when(view.getSelectedProfile()).thenReturn(PROFILE); + when(profileDao.loadProfileDataById(vm, PROFILE_ID)).thenReturn(new ByteArrayInputStream(PROFILE_DATA.getBytes(StandardCharsets.UTF_8))); + + listenerCaptor.getValue().actionPerformed(new ActionEvent<>(view, ProfileAction.PROFILE_SELECTED)); + + verify(view).setProfilingDetailData(isA(ProfilingResult.class)); + } + + private VmProfileController createController() { + return new VmProfileController(appService, agentInfoDao, profileDao, queue, clock, view, vm); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm-profiler/client-swing/src/test/java/com/redhat/thermostat/vm/profiler/client/swing/internal/VmProfileServiceTest.java Mon Nov 24 13:12:39 2014 -0500 @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.vm.profiler.client.swing.internal; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import org.junit.Test; + +import com.redhat.thermostat.common.Filter; +import com.redhat.thermostat.storage.core.VmRef; + +public class VmProfileServiceTest { + + @Test + public void worksWithDeadAndAliveVms() throws Exception { + VmRef vm = mock(VmRef.class); + + VmProfileService service = new VmProfileService(null, null, null, null); + Filter<VmRef> filter = service.getFilter(); + + assertTrue(filter.matches(vm)); + } + +}
--- a/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/ProfileDAO.java Fri Nov 21 11:02:34 2014 -0500 +++ b/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/ProfileDAO.java Mon Nov 24 13:12:39 2014 -0500 @@ -37,8 +37,10 @@ package com.redhat.thermostat.vm.profiler.common; import java.io.InputStream; +import java.util.List; import com.redhat.thermostat.annotations.Service; +import com.redhat.thermostat.common.model.Range; import com.redhat.thermostat.storage.core.VmRef; @Service @@ -46,7 +48,12 @@ void saveProfileData(ProfileInfo info, InputStream data); + List<ProfileInfo> getAllProfileInfo(VmRef vm, Range<Long> timeRange); + + InputStream loadProfileDataById(VmRef vm, String profileId); + /** @return {@code null} if no data is available */ InputStream loadLatestProfileData(VmRef vm); + }
--- a/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/internal/ProfileDAOImpl.java Fri Nov 21 11:02:34 2014 -0500 +++ b/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/internal/ProfileDAOImpl.java Mon Nov 24 13:12:39 2014 -0500 @@ -37,9 +37,11 @@ package com.redhat.thermostat.vm.profiler.common.internal; import java.io.InputStream; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import com.redhat.thermostat.common.model.Range; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.storage.core.Category; import com.redhat.thermostat.storage.core.Cursor; @@ -50,6 +52,7 @@ import com.redhat.thermostat.storage.core.StatementExecutionException; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.VmRef; +import com.redhat.thermostat.storage.core.VmTimeIntervalPojoListGetter; import com.redhat.thermostat.vm.profiler.common.ProfileDAO; import com.redhat.thermostat.vm.profiler.common.ProfileInfo; @@ -77,11 +80,24 @@ + Key.VM_ID.getName() + "' = ?s SORT '" + Key.TIMESTAMP.getName() + "' DSC LIMIT 1"; + static final String DESC_QUERY_BY_ID = "QUERY " + + CATEGORY.getName() + " WHERE '" + + Key.AGENT_ID.getName() + "' = ?s AND '" + + Key.VM_ID.getName() + "' = ?s AND '" + + Key.TIMESTAMP.getName() + "' = ?s LIMIT 1"; + + // internal information of VmTimeIntervalPojoListGetter being leaked :( + static final String DESC_INTERVAL_QUERY = String.format( + VmTimeIntervalPojoListGetter.VM_INTERVAL_QUERY_FORMAT, ProfileDAOImpl.CATEGORY.getName()); + private final Storage storage; + private final VmTimeIntervalPojoListGetter<ProfileInfo> getter; public ProfileDAOImpl(Storage storage) { this.storage = storage; this.storage.registerCategory(CATEGORY); + + this.getter = new VmTimeIntervalPojoListGetter<>(storage, CATEGORY); } @Override @@ -108,6 +124,18 @@ } @Override + public List<ProfileInfo> getAllProfileInfo(VmRef vm, Range<Long> timeRange) { + System.out.println("ProfileDAOImpl: getAllProfileInfo()"); + return getter.getLatest(vm, timeRange.getMin(), timeRange.getMax()); + } + + @Override + public InputStream loadProfileDataById(VmRef vm, String profileId) { + // TODO should we check whether this profileId is valid by querying the DB first? + return getProfileData(profileId); + } + + @Override public InputStream loadLatestProfileData(VmRef vm) { StatementDescriptor<ProfileInfo> desc = new StatementDescriptor<>(CATEGORY, DESC_QUERY_LATEST); PreparedStatement<ProfileInfo> prepared; @@ -120,8 +148,7 @@ return null; } ProfileInfo info = cursor.next(); - String profileId = info.getProfileId(); - return storage.loadFile(profileId); + return getProfileData(info.getProfileId()); } catch (DescriptorParsingException e) { logger.log(Level.SEVERE, "Preparing stmt '" + desc + "' failed!", e); } catch (StatementExecutionException e) { @@ -130,4 +157,7 @@ return null; } + private InputStream getProfileData(String profileId) { + return storage.loadFile(profileId); + } }
--- a/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/internal/ProfileDAOImplStatementDescriptorRegistration.java Fri Nov 21 11:02:34 2014 -0500 +++ b/vm-profiler/common/src/main/java/com/redhat/thermostat/vm/profiler/common/internal/ProfileDAOImplStatementDescriptorRegistration.java Mon Nov 24 13:12:39 2014 -0500 @@ -48,7 +48,9 @@ @Override public DescriptorMetadata getDescriptorMetadata(String descriptor, PreparedParameter[] params) { if (descriptor.equals(ProfileDAOImpl.DESC_ADD_PROFILE_INFO) - || descriptor.equals(ProfileDAOImpl.DESC_QUERY_LATEST)) { + || descriptor.equals(ProfileDAOImpl.DESC_QUERY_LATEST) + || descriptor.equals(ProfileDAOImpl.DESC_QUERY_BY_ID) + || descriptor.equals(ProfileDAOImpl.DESC_INTERVAL_QUERY)) { String agentId = (String)params[0].getValue(); String vmId = (String)params[1].getValue(); DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); @@ -62,7 +64,9 @@ public Set<String> getStatementDescriptors() { Set<String> results = new HashSet<>(); results.add(ProfileDAOImpl.DESC_ADD_PROFILE_INFO); + results.add(ProfileDAOImpl.DESC_QUERY_BY_ID); results.add(ProfileDAOImpl.DESC_QUERY_LATEST); + results.add(ProfileDAOImpl.DESC_INTERVAL_QUERY); return results; } }
--- a/vm-profiler/common/src/test/java/com/redhat/thermostat/vm/profiler/common/internal/ProfileDAOImplStatementDescriptorRegistrationTest.java Fri Nov 21 11:02:34 2014 -0500 +++ b/vm-profiler/common/src/test/java/com/redhat/thermostat/vm/profiler/common/internal/ProfileDAOImplStatementDescriptorRegistrationTest.java Mon Nov 24 13:12:39 2014 -0500 @@ -50,5 +50,7 @@ Set<String> names = registration.getStatementDescriptors(); assertTrue(names.contains(ProfileDAOImpl.DESC_ADD_PROFILE_INFO)); assertTrue(names.contains(ProfileDAOImpl.DESC_QUERY_LATEST)); + assertTrue(names.contains(ProfileDAOImpl.DESC_QUERY_BY_ID)); + assertTrue(names.contains(ProfileDAOImpl.DESC_INTERVAL_QUERY)); } }
--- a/vm-profiler/distribution/thermostat-plugin.xml Fri Nov 21 11:02:34 2014 -0500 +++ b/vm-profiler/distribution/thermostat-plugin.xml Mon Nov 24 13:12:39 2014 -0500 @@ -89,6 +89,14 @@ </commands> <extensions> <extension> + <name>gui</name> + <bundles> + <bundle><symbolic-name>com.redhat.thermostat.vm.profiler.common</symbolic-name><version>${project.version}</version></bundle> + <bundle><symbolic-name>com.redhat.thermostat.vm.profiler.client.core</symbolic-name><version>${project.version}</version></bundle> + <bundle><symbolic-name>com.redhat.thermostat.vm.profiler.client.swing</symbolic-name><version>${project.version}</version></bundle> + </bundles> + </extension> + <extension> <name>agent</name> <bundles> <bundle><symbolic-name>com.redhat.thermostat.vm.profiler.common</symbolic-name><version>${project.version}</version></bundle>
--- a/vm-profiler/jvm-agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/jvm/InstrumentationControl.java Fri Nov 21 11:02:34 2014 -0500 +++ b/vm-profiler/jvm-agent/src/main/java/com/redhat/thermostat/vm/profiler/agent/jvm/InstrumentationControl.java Mon Nov 24 13:12:39 2014 -0500 @@ -160,7 +160,7 @@ try (BufferedWriter out = Files.newBufferedWriter(output, StandardCharsets.UTF_8, options)) { Map<String, AtomicLong> data = ProfileRecorder.getInstance().getData(); for (Map.Entry<String, AtomicLong> entry : data.entrySet()) { - out.write(entry.getValue().get() + "\t" + entry.getKey()); + out.write(entry.getValue().get() + "\t" + entry.getKey() + "\n"); } System.out.println("AGENT: profiling data written to " + output.toString()); return output.toString();