All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.spf4j.ui.Explorer Maven / Gradle / Ivy

Go to download

A simple swing UI that allows you to visualize/export diagnostic files generates with the spf4j-core library: tsdb, ssdump...

There is a newer version: 8.10.0
Show newest version
/*
 * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * Additionally licensed with:
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.spf4j.ui;
//CHECKSTYLE:OFF
import com.google.common.annotations.VisibleForTesting;
import com.google.protobuf.CodedInputStream;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.KeyEvent;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.annotation.Nullable;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.DefaultEditorKit;
import org.spf4j.base.AbstractRunnable;
import org.spf4j.base.SysExits;
import org.spf4j.base.Throwables;
import org.spf4j.stackmonitor.SampleNode;
import org.spf4j.stackmonitor.Sampler;
import org.spf4j.stackmonitor.proto.Converter;
import org.spf4j.stackmonitor.proto.gen.ProtoSampleNodes;

/**
 * @author zoly
 */
@SuppressFBWarnings({"FCBL_FIELD_COULD_BE_LOCAL",
  "UP_UNUSED_PARAMETER", "S508C_NON_TRANSLATABLE_STRING", "SE_BAD_FIELD"})
public class Explorer extends javax.swing.JFrame {

  private static final long serialVersionUID = 1L;

  private static final Lock ERR_LOCK = new ReentrantLock();


  private File folder;

  private Sampler sampler;

  /**
   * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The
   * content of this method is always regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
  // //GEN-BEGIN:initComponents
  private void initComponents() {

    desktopPane = new javax.swing.JDesktopPane();
    menuBar = new javax.swing.JMenuBar();
    fileMenu = new javax.swing.JMenu();
    openMenuItem = new javax.swing.JMenuItem();
    fromTextMenuItem = new javax.swing.JMenuItem();
    exitMenuItem = new javax.swing.JMenuItem();
    editMenu = new javax.swing.JMenu();
    cutMenuItem = new javax.swing.JMenuItem();
    copyMenuItem = new javax.swing.JMenuItem();
    pasteMenuItem = new javax.swing.JMenuItem();
    deleteMenuItem = new javax.swing.JMenuItem();
    jMenu1 = new javax.swing.JMenu();
    jMenuItem1 = new javax.swing.JMenuItem();
    jMenuItem2 = new javax.swing.JMenuItem();
    helpMenu = new javax.swing.JMenu();
    contentMenuItem = new javax.swing.JMenuItem();
    aboutMenuItem = new javax.swing.JMenuItem();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

    desktopPane.setAutoscrolls(true);
    desktopPane.setDoubleBuffered(true);
    desktopPane.setPreferredSize(new java.awt.Dimension(800, 600));
    desktopPane.setLayout(null);

    fileMenu.setMnemonic('f');
    fileMenu.setText("File");

    openMenuItem.setMnemonic('o');
    openMenuItem.setText("Open");
    openMenuItem.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        openMenuItemActionPerformed(evt);
      }
    });
    fileMenu.add(openMenuItem);

    fromTextMenuItem.setMnemonic('o');
    fromTextMenuItem.setText("FromText");
    fromTextMenuItem.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        fromTextMenuItemActionPerformed(evt);
      }
    });
    fileMenu.add(fromTextMenuItem);

    exitMenuItem.setMnemonic('x');
    exitMenuItem.setText("Exit");
    exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        exitMenuItemActionPerformed(evt);
      }
    });
    fileMenu.add(exitMenuItem);

    menuBar.add(fileMenu);

    editMenu.setMnemonic('e');
    editMenu.setText("Edit");

    cutMenuItem.setMnemonic('t');
    cutMenuItem.setText("Cut");
    editMenu.add(cutMenuItem);

    copyMenuItem.setMnemonic('y');
    copyMenuItem.setText("Copy");
    editMenu.add(copyMenuItem);

    pasteMenuItem.setMnemonic('p');
    pasteMenuItem.setText("Paste");
    editMenu.add(pasteMenuItem);

    deleteMenuItem.setMnemonic('d');
    deleteMenuItem.setText("Delete");
    editMenu.add(deleteMenuItem);

    menuBar.add(editMenu);

    jMenu1.setText("SelfProfile");

    jMenuItem1.setText("Start");
    jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        jMenuItem1ActionPerformed(evt);
      }
    });
    jMenu1.add(jMenuItem1);

    jMenuItem2.setText("Stop & Display");
    jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        jMenuItem2ActionPerformed(evt);
      }
    });
    jMenu1.add(jMenuItem2);

    menuBar.add(jMenu1);

    helpMenu.setMnemonic('h');
    helpMenu.setText("Help");

    contentMenuItem.setMnemonic('c');
    contentMenuItem.setText("Contents");
    helpMenu.add(contentMenuItem);

    aboutMenuItem.setMnemonic('a');
    aboutMenuItem.setText("About");
    helpMenu.add(aboutMenuItem);

    menuBar.add(helpMenu);

    setJMenuBar(menuBar);

    org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
      .add(desktopPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 1149, Short.MAX_VALUE)
    );
    layout.setVerticalGroup(
      layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
      .add(desktopPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 668, Short.MAX_VALUE)
    );

    pack();
  }// //GEN-END:initComponents

  /**
   * Creates new form Explorer
   */
  @SuppressFBWarnings("PATH_TRAVERSAL_IN")
  public Explorer(final File... openFiles) throws IOException {
    if (openFiles.length == 0) {
      folder = new File(org.spf4j.base.Runtime.USER_DIR);
    } else {
      folder = openFiles[0].getParentFile();
    }
    initComponents();
    for (File file : openFiles) {
      openFile(file);
    }
  }

    private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
      System.exit(0);
    }//GEN-LAST:event_exitMenuItemActionPerformed

    private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMenuItemActionPerformed
      JFileChooser chooser = new JFileChooser();
      chooser.setName("openFileDialog");
      chooser.setMultiSelectionEnabled(true);
      chooser.setDialogType(JFileChooser.OPEN_DIALOG);
      chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
      chooser.setFileFilter(new Spf4jFileFilter());
      if (folder != null) {
        chooser.setCurrentDirectory(folder);
      }

      int returnVal = chooser.showOpenDialog(this);

      if (returnVal == JFileChooser.APPROVE_OPTION) {
        File [] files = chooser.getSelectedFiles();
        for (File file : files) {
          try {
            openFile(file);
          } catch (IOException ex) {
            throw new UncheckedIOException(ex);
          }
        }
      }
    }//GEN-LAST:event_openMenuItemActionPerformed

  /**
   * Create an Edit menu to support cut/copy/paste.
   */
  public JMenuBar createContextMenuBar() {
    JMenuItem menuItem = null;
    JMenuBar menuBar = new JMenuBar();
    JMenu mainMenu = new JMenu("Edit");
    mainMenu.setMnemonic(KeyEvent.VK_E);

    menuItem = new JMenuItem(new DefaultEditorKit.CutAction());
    menuItem.setText("Cut");
    menuItem.setMnemonic(KeyEvent.VK_X);
    mainMenu.add(menuItem);

    menuItem = new JMenuItem(new DefaultEditorKit.CopyAction());
    menuItem.setText("Copy");
    menuItem.setMnemonic(KeyEvent.VK_C);
    mainMenu.add(menuItem);

    menuItem = new JMenuItem(new DefaultEditorKit.PasteAction());
    menuItem.setText("Paste");
    menuItem.setMnemonic(KeyEvent.VK_V);
    mainMenu.add(menuItem);

    menuBar.add(mainMenu);
    return menuBar;
  }


  private void fromTextMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fromTextMenuItemActionPerformed

    final JDialog frame = new JDialog(this, "Enter json stack samples", true);
    frame.setName("fromTextDialog");
    frame.setJMenuBar(createContextMenuBar());
    TextEntryPanel panel = new TextEntryPanel((samples) -> {
        JInternalFrame f = new StackDumpJInternalFrame(samples, "text entry", true);
        frame.setVisible(false);
        f.setVisible(true);
        desktopPane.add(f, javax.swing.JLayeredPane.DEFAULT_LAYER);
    }, (ex) -> {
      JOptionPane.showMessageDialog(frame, "Invalid input " + ex);
      frame.setVisible(false);
      frame.dispose();
    });
    frame.getContentPane().add(panel);
    frame.pack();
    frame.setVisible(true);
  }//GEN-LAST:event_fromTextMenuItemActionPerformed

  private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed
    try {
      sampler = Sampler.getSampler(10, 100000, new File("."), "dump");
      sampler.start();
    } catch (InterruptedException ex) {
      Thread.currentThread().interrupt();
      throw new RuntimeException(ex);
    }
  }//GEN-LAST:event_jMenuItem1ActionPerformed

  private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed
    if (sampler != null) {
      try {
        sampler.stop();
      } catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
        throw new RuntimeException(ex);
      }
      Map samples = sampler.getStackCollectionsAndReset();
      for (Map.Entry entry : samples.entrySet()) {
        try {
          setFrames(entry.getValue(), "self:" + entry.getKey());
        } catch (IOException ex) {
          throw new UncheckedIOException(ex);
        }
      }
    }
  }//GEN-LAST:event_jMenuItem2ActionPerformed

  private void openFile(final File file) throws IOException {
    String fileName = file.getName();
    JInternalFrame frame;
    if (fileName.endsWith("tsdb")) {
      frame = new TSDBViewJInternalFrame(file);
      frame.setVisible(true);
      desktopPane.add(frame, javax.swing.JLayeredPane.DEFAULT_LAYER);
    } else if (fileName.endsWith("tsdb2")) {
      frame = new TSDB2ViewJInternalFrame(file);
      frame.setVisible(true);
      desktopPane.add(frame, javax.swing.JLayeredPane.DEFAULT_LAYER);
    } else if (fileName.endsWith("ssdump")) {
      SampleNode samples = loadLegacyFormat(file);
      setFrames(samples, fileName);
    } else if (fileName.endsWith("ssdump2")) {
      SampleNode samples = org.spf4j.ssdump2.Converter.load(file);
      setFrames(samples, fileName);
    } else if (fileName.endsWith("ssdump3")) {
      Map loadLabeledDumps = org.spf4j.ssdump2.Converter.loadLabeledDumps(file);
      for (Map.Entry entry : loadLabeledDumps.entrySet()) {
        setFrames(entry.getValue(), fileName + ':' + entry.getKey());
      }
    } else {
      throw new IOException("Unsupported file format " + fileName);
    }
  }

  private static SampleNode loadLegacyFormat(final File file) throws IOException {
    InputStream fis = Files.newInputStream(file.toPath());
    return loadLegacyFormat(fis);
  }

  @VisibleForTesting
  static SampleNode loadLegacyFormat(InputStream fis) throws IOException {
    try (BufferedInputStream bis = new BufferedInputStream(fis)) {
      final CodedInputStream is = CodedInputStream.newInstance(bis);
      is.setRecursionLimit(Short.MAX_VALUE);
      return Converter.fromProtoToSampleNode(ProtoSampleNodes.SampleNode.parseFrom(is));
    }
  }

  private void setFrames(SampleNode samples, String fileName) throws IOException {
    JInternalFrame frame = new StackDumpJInternalFrame(samples, fileName, false);
    frame.setVisible(true);
    desktopPane.add(frame, javax.swing.JLayeredPane.DEFAULT_LAYER);
  }

  @Nullable
  private static Frame findActiveFrame() {
    Frame[] frames = JFrame.getFrames();
    for (Frame frame : frames) {
      if (frame.isVisible()) {
        return frame;
      }
    }
    return null;
  }


  /**
   * @param args the command line arguments
   */
  public static void main(final String[] args) {
    Thread.setDefaultUncaughtExceptionHandler((Thread t, Throwable e) -> {
      Frame frame = findActiveFrame();
      if (frame != null) {
        try {
          if (ERR_LOCK.tryLock(100, TimeUnit.MILLISECONDS)) {
            try {
              JTextArea textArea = new JTextArea(Throwables.toString(e));
              JScrollPane scrollPane = new JScrollPane(textArea);
              textArea.setLineWrap(true);
              textArea.setWrapStyleWord(true);
              scrollPane.setPreferredSize( new Dimension( 500, 500 ) );
              JOptionPane.showConfirmDialog(frame, scrollPane, "Exception",
                      JOptionPane.OK_OPTION, JOptionPane.ERROR_MESSAGE);
            } finally {
              ERR_LOCK.unlock();
            }
          } else {
            Throwables.writeTo(e, System.err, Throwables.PackageDetail.SHORT);
          }
        } catch (InterruptedException ex) {
          Thread.currentThread().interrupt();
          return;
        }
      } else {
        Throwables.writeTo(e, System.err, Throwables.PackageDetail.SHORT);
      }
      if (Throwables.isNonRecoverable(e)) {
        System.exit(SysExits.EX_SOFTWARE.exitCode());
      }
    });
    System.setProperty("spf4j.tsdb2.lenientRead", "true");
    /* Set the Nimbus look and feel */
    //
    /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
     */
    try {
      for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
        if ("Nimbus".equals(info.getName())) {
          javax.swing.UIManager.setLookAndFeel(info.getClassName());
          break;
        }
      }
    } catch (ClassNotFoundException ex) {
      java.util.logging.Logger.getLogger(Explorer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
      java.util.logging.Logger.getLogger(Explorer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
      java.util.logging.Logger.getLogger(Explorer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
      java.util.logging.Logger.getLogger(Explorer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }
    //

    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new AbstractRunnable(false) {
      @Override
      @SuppressFBWarnings("PATH_TRAVERSAL_IN")
      public void doRun() throws IOException {
        File[] files = new File[args.length];
        for (int i = 0; i < args.length; i++) {
          files[i] = new File(args[i]);
        }
        new Explorer(files).setVisible(true);
      }
    });
  }
  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JMenuItem aboutMenuItem;
  private javax.swing.JMenuItem contentMenuItem;
  private javax.swing.JMenuItem copyMenuItem;
  private javax.swing.JMenuItem cutMenuItem;
  private javax.swing.JMenuItem deleteMenuItem;
  private javax.swing.JDesktopPane desktopPane;
  private javax.swing.JMenu editMenu;
  private javax.swing.JMenuItem exitMenuItem;
  private javax.swing.JMenu fileMenu;
  private javax.swing.JMenuItem fromTextMenuItem;
  private javax.swing.JMenu helpMenu;
  private javax.swing.JMenu jMenu1;
  private javax.swing.JMenuItem jMenuItem1;
  private javax.swing.JMenuItem jMenuItem2;
  private javax.swing.JMenuBar menuBar;
  private javax.swing.JMenuItem openMenuItem;
  private javax.swing.JMenuItem pasteMenuItem;
  // End of variables declaration//GEN-END:variables

  private static class Spf4jFileFilter extends FileFilter {

    @Override
    public boolean accept(final File f) {
      if (f.isDirectory()) {
        return true;
      } else if (f.isFile()) {
        String name = f.getName();
        return (name.endsWith("tsdb") || name.endsWith("tsdb2")
                || name.endsWith("ssdump") || name.endsWith("ssdump2") || name.endsWith("ssdump3"));
      } else {
        return false;
      }
    }

    @Override
    public String getDescription() {
      return "spf4j dumps";
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy