1 /*
   2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
   3  * 
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * The contents of this file are subject to the terms of either the Universal Permissive License
   7  * v 1.0 as shown at http://oss.oracle.com/licenses/upl
   8  *
   9  * or the following license:
  10  *
  11  * Redistribution and use in source and binary forms, with or without modification, are permitted
  12  * provided that the following conditions are met:
  13  * 
  14  * 1. Redistributions of source code must retain the above copyright notice, this list of conditions
  15  * and the following disclaimer.
  16  * 
  17  * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
  18  * conditions and the following disclaimer in the documentation and/or other materials provided with
  19  * the distribution.
  20  * 
  21  * 3. Neither the name of the copyright holder nor the names of its contributors may be used to
  22  * endorse or promote products derived from this software without specific prior written permission.
  23  * 
  24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
  25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  26  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
  27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
  31  * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  */
  33 package org.openjdk.jmc.flightrecorder.ui.pages;
  34 
  35 import java.util.Collections;
  36 import java.util.HashSet;
  37 import java.util.Set;
  38 
  39 import org.eclipse.jface.resource.ImageDescriptor;
  40 import org.eclipse.jface.viewers.ColumnViewer;
  41 import org.eclipse.swt.SWT;
  42 import org.eclipse.swt.custom.SashForm;
  43 import org.eclipse.swt.layout.GridData;
  44 import org.eclipse.swt.widgets.Composite;
  45 import org.eclipse.ui.forms.widgets.Form;
  46 import org.eclipse.ui.forms.widgets.FormToolkit;
  47 import org.eclipse.ui.forms.widgets.Section;
  48 
  49 import org.openjdk.jmc.common.IState;
  50 import org.openjdk.jmc.common.IWritableState;
  51 import org.openjdk.jmc.common.item.IAccessorFactory;
  52 import org.openjdk.jmc.common.item.IItemFilter;
  53 import org.openjdk.jmc.common.item.IMemberAccessor;
  54 import org.openjdk.jmc.common.item.IType;
  55 import org.openjdk.jmc.common.item.ItemFilters;
  56 import org.openjdk.jmc.flightrecorder.jdk.JdkAggregators;
  57 import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes;
  58 import org.openjdk.jmc.flightrecorder.jdk.JdkFilters;
  59 import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs;
  60 import org.openjdk.jmc.flightrecorder.rules.util.JfrRuleTopics;
  61 import org.openjdk.jmc.flightrecorder.ui.FlightRecorderUI;
  62 import org.openjdk.jmc.flightrecorder.ui.IDataPageFactory;
  63 import org.openjdk.jmc.flightrecorder.ui.IDisplayablePage;
  64 import org.openjdk.jmc.flightrecorder.ui.IPageContainer;
  65 import org.openjdk.jmc.flightrecorder.ui.IPageDefinition;
  66 import org.openjdk.jmc.flightrecorder.ui.IPageUI;
  67 import org.openjdk.jmc.flightrecorder.ui.StreamModel;
  68 import org.openjdk.jmc.flightrecorder.ui.common.AbstractDataPage;
  69 import org.openjdk.jmc.flightrecorder.ui.common.DataPageToolkit;
  70 import org.openjdk.jmc.flightrecorder.ui.common.FilterComponent;
  71 import org.openjdk.jmc.flightrecorder.ui.common.ImageConstants;
  72 import org.openjdk.jmc.flightrecorder.ui.common.ItemAggregateViewer;
  73 import org.openjdk.jmc.flightrecorder.ui.common.ItemHistogram;
  74 import org.openjdk.jmc.flightrecorder.ui.common.ItemHistogram.CompositeKeyHistogramBuilder;
  75 import org.openjdk.jmc.flightrecorder.ui.messages.internal.Messages;
  76 import org.openjdk.jmc.ui.column.ColumnManager.SelectionState;
  77 import org.openjdk.jmc.ui.column.ColumnMenusFactory;
  78 import org.openjdk.jmc.ui.column.TableSettings;
  79 import org.openjdk.jmc.ui.handlers.MCContextMenuManager;
  80 import org.openjdk.jmc.ui.misc.CompositeToolkit;
  81 import org.openjdk.jmc.ui.misc.PersistableSashForm;
  82 
  83 public class JVMInformationPage extends AbstractDataPage {
  84         public static class JVMInformationPageFactory implements IDataPageFactory {
  85 
  86                 @Override
  87                 public String getName(IState state) {
  88                         return Messages.JVMInformationPage_PAGE_NAME;
  89                 }
  90 
  91                 @Override
  92                 public ImageDescriptor getImageDescriptor(IState state) {
  93                         return FlightRecorderUI.getDefault().getMCImageDescriptor(ImageConstants.PAGE_JVM_INTERNALS);
  94                 }
  95 
  96                 @Override
  97                 public String[] getTopics(IState state) {
  98                         return new String[] {JfrRuleTopics.JVM_INFORMATION_TOPIC};
  99                 }
 100 
 101                 @Override
 102                 public IDisplayablePage createPage(IPageDefinition dpd, StreamModel items, IPageContainer editor) {
 103                         return new JVMInformationPage(dpd, items, editor);
 104                 }
 105 
 106         }
 107 
 108         private static final Set<String> FLAGS;
 109 
 110         static {
 111                 Set<String> types = new HashSet<>();
 112                 types.add(JdkTypeIDs.LONG_FLAG);
 113                 types.add(JdkTypeIDs.ULONG_FLAG);
 114                 types.add(JdkTypeIDs.DOUBLE_FLAG);
 115                 types.add(JdkTypeIDs.BOOLEAN_FLAG);
 116                 types.add(JdkTypeIDs.STRING_FLAG);
 117                 types.add(JdkTypeIDs.INT_FLAG);
 118                 types.add(JdkTypeIDs.UINT_FLAG);
 119                 FLAGS = Collections.unmodifiableSet(types);
 120         }
 121 
 122         private static final IItemFilter FLAGS_FILTER = ItemFilters.type(FLAGS);
 123 
 124         private static final IAccessorFactory<?> FLAG_VALUE_FIELD = new IAccessorFactory<Object>() {
 125 
 126                 @Override
 127                 public <T> IMemberAccessor<?, T> getAccessor(IType<T> type) {
 128                         switch (type.getIdentifier()) {
 129                         case JdkTypeIDs.LONG_FLAG:
 130                         case JdkTypeIDs.ULONG_FLAG:
 131                         case JdkTypeIDs.DOUBLE_FLAG:
 132                         case JdkTypeIDs.INT_FLAG:
 133                         case JdkTypeIDs.UINT_FLAG:
 134                                 return JdkAttributes.FLAG_VALUE_NUMBER.getAccessor(type);
 135                         case JdkTypeIDs.BOOLEAN_FLAG:
 136                                 return JdkAttributes.FLAG_VALUE_BOOLEAN.getAccessor(type);
 137                         case JdkTypeIDs.STRING_FLAG:
 138                                 return JdkAttributes.FLAG_VALUE_TEXT.getAccessor(type);
 139                         default:
 140                                 // FIXME: Return fallback function instead?
 141                                 return null;
 142                         }
 143                 }
 144 
 145         };
 146 
 147         private class JVMInformationUi implements IPageUI {
 148 
 149                 private final ItemAggregateViewer infoViewer;
 150                 private final ItemHistogram allFlagsTable;
 151                 private FilterComponent allFlagsFilter;
 152                 private final SashForm sash;
 153 
 154                 JVMInformationUi(Composite parent, FormToolkit toolkit, IPageContainer pageContainer, IState state) {
 155                         Form form = DataPageToolkit.createForm(parent, toolkit, getName(), getIcon());
 156 
 157                         sash = new SashForm(form.getBody(), SWT.HORIZONTAL);
 158                         sash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
 159 
 160                         Section jvmInfSection = CompositeToolkit.createSection(sash, toolkit,
 161                                         Messages.JVMInformationPage_SECTION_JVM_INFO);
 162                         infoViewer = new ItemAggregateViewer(jvmInfSection, toolkit);
 163                         infoViewer.addAggregate(JdkAggregators.JVM_START_TIME);
 164                         infoViewer.addAggregate(JdkAggregators.JVM_NAME);
 165                         infoViewer.addAggregate(JdkAggregators.JVM_VERSION);
 166                         infoViewer.addAggregate(JdkAggregators.JVM_ARGUMENTS);
 167                         infoViewer.addAggregate(JdkAggregators.JAVA_ARGUMENTS);
 168                         infoViewer.addAggregate(JdkAggregators.JVM_SHUTDOWN_TIME);
 169                         infoViewer.addAggregate(JdkAggregators.JVM_SHUTDOWN_REASON);
 170                         jvmInfSection.setClient(infoViewer.getControl());
 171 
 172                         Section allFlagsSection = CompositeToolkit.createSection(sash, toolkit,
 173                                         Messages.JVMInformationPage_SECTION_JVM_FLAGS);
 174                         allFlagsTable = FLAG_HISTOGRAM.buildWithoutBorder(allFlagsSection,
 175                                         new TableSettings(state.getChild(JVM_FLAGS)));
 176                         allFlagsFilter = FilterComponent.createFilterComponent(allFlagsTable, flagsFilter,
 177                                         getDataSource().getItems().apply(FLAGS_FILTER), pageContainer.getSelectionStore()::getSelections,
 178                                         this::onFilterChange);
 179                         MCContextMenuManager mm = MCContextMenuManager.create(allFlagsTable.getManager().getViewer().getControl());
 180                         ColumnMenusFactory.addDefaultMenus(allFlagsTable.getManager(), mm);
 181                         mm.add(allFlagsFilter.getShowFilterAction());
 182                         mm.add(allFlagsFilter.getShowSearchAction());
 183                         allFlagsSection.setClient(allFlagsFilter.getComponent());
 184 
 185                         ColumnViewer viewer = allFlagsTable.getManager().getViewer();
 186                         viewer.addSelectionChangedListener(
 187                                         e -> pageContainer.showSelection(allFlagsTable.getSelection().getItems()));
 188 
 189                         PersistableSashForm.loadState(sash, state.getChild(SASH));
 190                         allFlagsFilter.loadState(getState().getChild(JVM_FLAGS_FILTER));
 191 
 192                         infoViewer.setValues(getDataSource().getItems());
 193                         allFlagsTable.show(getDataSource().getItems().apply(FLAGS_FILTER));
 194                         onFilterChange(flagsFilter);
 195                         addResultActions(form);
 196                         allFlagsTable.getManager().setSelectionState(flagsSelection);
 197                 }
 198 
 199                 private void onFilterChange(IItemFilter filter) {
 200                         allFlagsFilter.filterChangeHelper(filter, allFlagsTable, getDataSource().getItems().apply(FLAGS_FILTER));
 201                         flagsFilter = filter;
 202                 }
 203 
 204                 @Override
 205                 public void saveTo(IWritableState memento) {
 206                         allFlagsTable.getManager().getSettings().saveState(memento.createChild(JVM_FLAGS));
 207                         allFlagsFilter.saveState(memento.createChild(JVM_FLAGS_FILTER));
 208                         PersistableSashForm.saveState(sash, memento.createChild(SASH));
 209 
 210                         saveToLocal();
 211                 }
 212 
 213                 private void saveToLocal() {
 214                         flagsSelection = allFlagsTable.getManager().getSelectionState();
 215                 }
 216 
 217         }
 218 
 219         private static final String SASH = "sash"; //$NON-NLS-1$
 220         private static final String JVM_FLAGS = "jvmFlags"; //$NON-NLS-1$
 221         private static final String JVM_FLAGS_FILTER = "jvmFlagsFilter"; //$NON-NLS-1$
 222 
 223         private static final String FLAG_VALUE_COL_ID = "value"; //$NON-NLS-1$
 224         private static final CompositeKeyHistogramBuilder FLAG_HISTOGRAM = new CompositeKeyHistogramBuilder();
 225         static {
 226                 FLAG_HISTOGRAM.addKeyColumn(JdkAttributes.FLAG_NAME);
 227                 FLAG_HISTOGRAM.addKeyColumn(JdkAttributes.FLAG_ORIGIN);
 228                 FLAG_HISTOGRAM.addKeyColumn(FLAG_VALUE_COL_ID, Messages.JVMInformationPage_COLUMN_VALUE, FLAG_VALUE_FIELD);
 229         }
 230 
 231         private IItemFilter flagsFilter;
 232         private SelectionState flagsSelection;
 233 
 234         @Override
 235         public IPageUI display(Composite parent, FormToolkit toolkit, IPageContainer pageContainer, IState state) {
 236                 return new JVMInformationUi(parent, toolkit, pageContainer, state);
 237         }
 238 
 239         public JVMInformationPage(IPageDefinition dpd, StreamModel items, IPageContainer editor) {
 240                 super(dpd, items, editor);
 241         }
 242 
 243         @Override
 244         public IItemFilter getDefaultSelectionFilter() {
 245                 return ItemFilters.or(FLAGS_FILTER, JdkFilters.VM_INFO);
 246         }
 247 }