/* * Copyright, Aspect Security, Inc. * * This file is part of JavaSnoop. * * JavaSnoop 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 3 of the License, or * (at your option) any later version. * * JavaSnoop 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 JavaSnoop. If not, see <http://www.gnu.org/licenses/>. */ package com.aspect.snoop.ui.choose.process; import com.aspect.snoop.SnoopSession; import com.aspect.snoop.util.ClasspathUtil; import com.aspect.snoop.util.UIUtil; import com.sun.tools.attach.VirtualMachineDescriptor; import java.awt.Color; import java.awt.Component; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.net.URISyntaxException; import java.util.Set; import java.util.Vector; import javax.swing.event.ListSelectionEvent; import org.jdesktop.application.Action; import sun.jvmstat.monitor.HostIdentifier; import sun.jvmstat.monitor.MonitorException; import sun.jvmstat.monitor.MonitoredHost; import sun.jvmstat.monitor.MonitoredVm; import sun.jvmstat.monitor.MonitoredVmUtil; import sun.jvmstat.monitor.VmIdentifier; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.IOException; import java.lang.management.ManagementFactory; import javax.swing.DefaultListCellRenderer; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.event.ListSelectionListener; import org.apache.log4j.Logger; public class ChooseProcessView extends javax.swing.JDialog { private static final Logger logger = Logger.getLogger(ChooseProcessView.class); private String pid; SnoopSession session; public ChooseProcessView(JFrame parent, boolean modal) { super(parent, modal); initComponents(); lstJavaProcesses.setListData(new String[0]); lstJavaProcesses.setCellRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent( JList list, Object value, int index, boolean selected, boolean hasFocus) { super.getListCellRendererComponent( list, value, index, selected, hasFocus); setText(getValueString(value)); return this; } private String getValueString(Object value) { String returnString = "null"; if (value != null) { if (value instanceof VirtualMachineDescriptor) { VirtualMachineDescriptor vmd = (VirtualMachineDescriptor)value; returnString = "[PID=" + vmd.id() +"] " + vmd.displayName(); } else if (value instanceof JVMDescriptor) { JVMDescriptor vmd = (JVMDescriptor)value; returnString = "[PID=" + vmd.getId() +"] " + vmd.getTitle(); if (!vmd.isAttachable()) this.setForeground(Color.gray); } else { returnString = "???: " + value.toString(); } } return returnString; } }); pid = null; loadProcesses(); final JFrame p = parent; lstJavaProcesses.addListSelectionListener( new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if ( ! lstJavaProcesses.isSelectionEmpty() ) { JVMDescriptor desc = (JVMDescriptor)lstJavaProcesses.getSelectedValue(); lblMainArgs.setText(desc.getMainArguments()); lblVmArgs.setText(desc.getJVMArguments()); lblPid.setText(desc.getId()); lblVmVersion.setText(desc.getVMVersion()); lblMainClass.setText(desc.getMainClass()); lblJar.setText(desc.getJar()); btnCopyToClipboard.setEnabled(true); btnUseAndAttach.setEnabled(true); } else { String nsy = "(none selected yet)"; lblMainArgs.setText(nsy); lblVmArgs.setText(nsy); lblPid.setText(nsy); lblVmVersion.setText(nsy); lblMainClass.setText(nsy); lblJar.setText(nsy); btnCopyToClipboard.setEnabled(false); btnUseAndAttach.setEnabled(false); } } }); lstJavaProcesses.addMouseListener( new MouseListener() { public void mouseClicked(MouseEvent e) { if ( e.getClickCount() == 2 ) { // user double clicked an item selection JVMDescriptor selection = (JVMDescriptor)lstJavaProcesses.getSelectedValue(); if ( ! selection.isAttachable() ) { UIUtil.showErrorMessage(p, "Sorry, can't attach to that VM. It's probably running on an old version of Java."); return; } finalizeSelection(); dispose(); } } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } } ); } /** 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") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jScrollPane1 = new javax.swing.JScrollPane(); lstJavaProcesses = new javax.swing.JList(); jLabel1 = new javax.swing.JLabel(); lblPid = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); lblVmArgs = new javax.swing.JLabel(); jLabel5 = new javax.swing.JLabel(); lblMainArgs = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); lblVmVersion = new javax.swing.JLabel(); jLabel4 = new javax.swing.JLabel(); lblMainClass = new javax.swing.JLabel(); btnUseAndAttach = new javax.swing.JButton(); btnCopyToClipboard = new javax.swing.JButton(); jLabel6 = new javax.swing.JLabel(); lblJar = new javax.swing.JLabel(); btnUseAndAttachAndClobber = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(com.aspect.snoop.JavaSnoop.class).getContext().getResourceMap(ChooseProcessView.class); setTitle(resourceMap.getString("Form.title")); // NOI18N setModalityType(java.awt.Dialog.ModalityType.APPLICATION_MODAL); setName("Form"); // NOI18N setResizable(false); jScrollPane1.setName("jScrollPane1"); // NOI18N lstJavaProcesses.setModel(new javax.swing.AbstractListModel() { String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }; public int getSize() { return strings.length; } public Object getElementAt(int i) { return strings[i]; } }); lstJavaProcesses.setName("lstJavaProcesses"); // NOI18N jScrollPane1.setViewportView(lstJavaProcesses); jLabel1.setText(resourceMap.getString("jLabel1.text")); // NOI18N jLabel1.setName("jLabel1"); // NOI18N lblPid.setText(resourceMap.getString("lblPid.text")); // NOI18N lblPid.setName("lblPid"); // NOI18N jLabel3.setText(resourceMap.getString("jLabel3.text")); // NOI18N jLabel3.setName("jLabel3"); // NOI18N lblVmArgs.setText(resourceMap.getString("lblVmArgs.text")); // NOI18N lblVmArgs.setName("lblVmArgs"); // NOI18N jLabel5.setText(resourceMap.getString("jLabel5.text")); // NOI18N jLabel5.setName("jLabel5"); // NOI18N lblMainArgs.setText(resourceMap.getString("lblMainArgs.text")); // NOI18N lblMainArgs.setName("lblMainArgs"); // NOI18N jLabel2.setText(resourceMap.getString("jLabel2.text")); // NOI18N jLabel2.setName("jLabel2"); // NOI18N lblVmVersion.setText(resourceMap.getString("lblVmVersion.text")); // NOI18N lblVmVersion.setName("lblVmVersion"); // NOI18N jLabel4.setText(resourceMap.getString("jLabel4.text")); // NOI18N jLabel4.setName("jLabel4"); // NOI18N lblMainClass.setText(resourceMap.getString("lblMainClass.text")); // NOI18N lblMainClass.setName("lblMainClass"); // NOI18N javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(com.aspect.snoop.JavaSnoop.class).getContext().getActionMap(ChooseProcessView.class, this); btnUseAndAttach.setAction(actionMap.get("useAndAttach")); // NOI18N btnUseAndAttach.setText(resourceMap.getString("btnUseAndAttach.text")); // NOI18N btnUseAndAttach.setToolTipText(resourceMap.getString("btnUseAndAttach.toolTipText")); // NOI18N btnUseAndAttach.setName("btnUseAndAttach"); // NOI18N btnCopyToClipboard.setAction(actionMap.get("copyToClipboard")); // NOI18N btnCopyToClipboard.setText(resourceMap.getString("btnCopyToClipboard.text")); // NOI18N btnCopyToClipboard.setToolTipText(resourceMap.getString("btnCopyToClipboard.toolTipText")); // NOI18N btnCopyToClipboard.setName("btnCopyToClipboard"); // NOI18N jLabel6.setText(resourceMap.getString("jLabel6.text")); // NOI18N jLabel6.setName("jLabel6"); // NOI18N lblJar.setText(resourceMap.getString("lblJar.text")); // NOI18N lblJar.setName("lblJar"); // NOI18N btnUseAndAttachAndClobber.setAction(actionMap.get("useAndAttachWithClobbering")); // NOI18N btnUseAndAttachAndClobber.setText(resourceMap.getString("btnUseAndAttachAndClobber.text")); // NOI18N btnUseAndAttachAndClobber.setToolTipText(resourceMap.getString("btnUseAndAttachAndClobber.toolTipText")); // NOI18N btnUseAndAttachAndClobber.setName("btnUseAndAttachAndClobber"); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 598, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addGap(10, 10, 10) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jLabel1) .addComponent(jLabel3) .addComponent(jLabel5) .addComponent(jLabel4) .addComponent(jLabel2) .addComponent(jLabel6)) .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(lblPid, javax.swing.GroupLayout.PREFERRED_SIZE, 134, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblVmArgs, javax.swing.GroupLayout.PREFERRED_SIZE, 357, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblMainArgs, javax.swing.GroupLayout.PREFERRED_SIZE, 357, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(lblVmVersion, javax.swing.GroupLayout.PREFERRED_SIZE, 186, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblJar, javax.swing.GroupLayout.PREFERRED_SIZE, 357, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblMainClass, javax.swing.GroupLayout.PREFERRED_SIZE, 346, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(6, 6, 6) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(btnUseAndAttach) .addComponent(btnCopyToClipboard))))) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap(421, Short.MAX_VALUE) .addComponent(btnUseAndAttachAndClobber))) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 112, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jLabel1) .addGap(6, 6, 6) .addComponent(jLabel3) .addGap(7, 7, 7) .addComponent(jLabel5) .addGap(7, 7, 7) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(jLabel4) .addGap(6, 6, 6) .addComponent(jLabel2) .addGap(7, 7, 7) .addComponent(jLabel6)) .addGroup(layout.createSequentialGroup() .addGap(3, 3, 3) .addComponent(btnCopyToClipboard) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(btnUseAndAttach)))) .addGroup(layout.createSequentialGroup() .addComponent(lblPid) .addGap(6, 6, 6) .addComponent(lblVmArgs) .addGap(6, 6, 6) .addComponent(lblMainArgs, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(6, 6, 6) .addComponent(lblMainClass) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(lblVmVersion, javax.swing.GroupLayout.PREFERRED_SIZE, 15, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(6, 6, 6) .addComponent(lblJar))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(btnUseAndAttachAndClobber) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); pack(); }// </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnCopyToClipboard; private javax.swing.JButton btnUseAndAttach; private javax.swing.JButton btnUseAndAttachAndClobber; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel4; private javax.swing.JLabel jLabel5; private javax.swing.JLabel jLabel6; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JLabel lblJar; private javax.swing.JLabel lblMainArgs; private javax.swing.JLabel lblMainClass; private javax.swing.JLabel lblPid; private javax.swing.JLabel lblVmArgs; private javax.swing.JLabel lblVmVersion; private javax.swing.JList lstJavaProcesses; // End of variables declaration//GEN-END:variables private final static boolean JPS_SHOW_JVM_ARGS = false; private final static boolean JPS_SHOW_LONG_PATHS = true; private final static boolean JPS_DEBUG = true; private void loadProcesses() { // Get descriptors for all JVM processes (JDK 1.6+) // List<VirtualMachineDescriptor> list = VirtualMachine.list(); // lstJavaProcesses.setListData(new Vector<VirtualMachineDescriptor>(list)); // Get descriptors for all JVM processes (JDK 1.5+) Vector<JVMDescriptor> vmds = new Vector<JVMDescriptor>(); try { HostIdentifier hostId = null; try { hostId = new HostIdentifier("localhost"); } catch (URISyntaxException e1) { e1.printStackTrace(); } MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(hostId); // Get the set of active JVMs on the specified host Set<Integer> jvmids = monitoredHost.activeVms(); for (Integer jvmid: jvmids) { StringBuilder output = new StringBuilder(); Throwable lastError = null; String jvmIdString = jvmid.toString(); output.append(jvmIdString); MonitoredVm vm = null; String vmidString = "//" + jvmIdString + "?mode=r"; try { VmIdentifier id = new VmIdentifier(vmidString); vm = monitoredHost.getMonitoredVm(id, 0); } catch (Exception e) { lastError = e; } finally { if (vm == null) { // A JVM may have died before we got a chance to inspect it output.append(" -- process information unavailable"); if (JPS_DEBUG) { if ((lastError != null) && (lastError.getMessage() != null)) { output.append("\n\t"); output.append(lastError.getMessage()); } } continue; } } output.append(" "); output.append(MonitoredVmUtil.mainClass(vm, JPS_SHOW_LONG_PATHS)); if (JPS_SHOW_JVM_ARGS) { String jvmArgs = MonitoredVmUtil.jvmArgs(vm); if (jvmArgs != null && jvmArgs.length() > 0) { output.append(" ").append(jvmArgs); } } String mainClassName = MonitoredVmUtil.mainClass(vm, true); boolean isAttachable = isAttachable(jvmIdString); JVMDescriptor desc = new JVMDescriptor(jvmIdString, mainClassName, isAttachable); desc.setJVMArguments(MonitoredVmUtil.jvmArgs(vm)); desc.setMainArguments(MonitoredVmUtil.mainArgs(vm)); desc.setCommandLine(MonitoredVmUtil.commandLine(vm)); desc.setVMVersion(MonitoredVmUtil.vmVersion(vm)); if ( mainClassName.length() == 0 ) { mainClassName = desc.getCommandLine(); } else if ( mainClassName.endsWith(".jar") ) { desc.setJar(mainClassName); try { desc.setMainClass(ClasspathUtil.getMainClassFromJarFile(mainClassName)); } catch (IOException ioe) { ioe.printStackTrace(); } } else { desc.setMainClass(mainClassName); desc.setJar(""); } desc.setMainClass(MonitoredVmUtil.mainClass(vm, true)); String currentPid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0]; if ( ! currentPid.equals(desc.getId()) ) { vmds.add(desc); } monitoredHost.detach(vm); } } catch (MonitorException e) { logger.error(e); } lstJavaProcesses.setListData(vmds); } private boolean isAttachable(String id) { boolean attachable = false; MonitoredVm mvm = null; try { VmIdentifier vmid = new VmIdentifier(id); MonitoredHost host = MonitoredHost.getMonitoredHost(vmid); mvm = host.getMonitoredVm(vmid); if (MonitoredVmUtil.isAttachable(mvm)) { attachable = true; } else { String lolilol = new String("lolilol"); /** if (MonitoredVmUtil.isKernelVM(mvm)) { logger.trace("Kernel VM does not support the attach mechanism"); } else { logger.trace("The VM does not support the attach mechanism for pid " + id); } * **/ } } catch (Throwable t) { // we do not know what this id is if (t instanceof ThreadDeath) { ThreadDeath td = (ThreadDeath) t; throw td; } } finally { if (mvm != null) { mvm.detach(); } } return attachable; } private void finalizeSelection() { JVMDescriptor desc = (JVMDescriptor)lstJavaProcesses.getSelectedValue(); pid = desc.getId(); } public String getPid() { return pid; } @Action public void useAndAttach() { if ( lstJavaProcesses.isSelectionEmpty() ) { return; } JVMDescriptor jvm = (JVMDescriptor)lstJavaProcesses.getSelectedValue(); this.session = toSession(jvm); finalizeSelection(); dispose(); } @Action public void useAndDispose() { if ( lstJavaProcesses.isSelectionEmpty() ) { return; } JVMDescriptor jvm = (JVMDescriptor)lstJavaProcesses.getSelectedValue(); session = toSession(jvm); dispose(); } public SnoopSession getSession() { return session; } private SnoopSession toSession(JVMDescriptor jvm) { SnoopSession sess = new SnoopSession(); sess.setArguments(jvm.getMainArguments()); sess.setJavaArguments(jvm.getJVMArguments()); sess.setProcessId(Integer.parseInt(jvm.getId())); sess.setClasspathString(jvm.getJar()); sess.setMainClass(jvm.getMainClass()); return sess; } @Action public void copyToClipboard() { if ( lstJavaProcesses.isSelectionEmpty() ) { return; } String nl = System.getProperty("line.separator"); JVMDescriptor jvm = (JVMDescriptor)lstJavaProcesses.getSelectedValue(); StringBuilder sb = new StringBuilder(200); sb.append("PID: ").append(jvm.getId()).append(nl); sb.append("Main class: ").append(jvm.getMainClass()).append(nl); sb.append("Main arguments: ").append(jvm.getMainArguments()).append(nl); if ( jvm.getJar().length() > 0 ) { sb.append("Jar file: ").append(jvm.getJar()).append(nl); } sb.append("JVM arguments: ").append(jvm.getJVMArguments()).append(nl); sb.append("VM version: ").append(jvm.getVMVersion()); StringSelection buffer = new StringSelection(sb.toString()); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(buffer, buffer); } @Action public void useAndAttachWithClobbering() { if ( lstJavaProcesses.isSelectionEmpty() ) { return; } JVMDescriptor jvm = (JVMDescriptor)lstJavaProcesses.getSelectedValue(); this.session = toSession(jvm); session.setCloberLookAndFeel(true); finalizeSelection(); dispose(); } }