1/*
2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.tools.jcmd;
27
28import java.io.InputStream;
29import java.io.IOException;
30import java.io.UnsupportedEncodingException;
31import java.util.List;
32import java.util.Collection;
33import java.util.Collections;
34import java.util.Comparator;
35import java.net.URISyntaxException;
36
37import com.sun.tools.attach.AttachOperationFailedException;
38import com.sun.tools.attach.VirtualMachine;
39import com.sun.tools.attach.VirtualMachineDescriptor;
40import com.sun.tools.attach.AttachNotSupportedException;
41
42import sun.tools.attach.HotSpotVirtualMachine;
43import sun.tools.common.ProcessArgumentMatcher;
44import sun.tools.jstat.JStatLogger;
45import sun.jvmstat.monitor.Monitor;
46import sun.jvmstat.monitor.MonitoredHost;
47import sun.jvmstat.monitor.MonitoredVm;
48import sun.jvmstat.monitor.MonitorException;
49import sun.jvmstat.monitor.VmIdentifier;
50
51public class JCmd {
52    public static void main(String[] args) {
53        Arguments arg = null;
54        try {
55            arg = new Arguments(args);
56        } catch (IllegalArgumentException ex) {
57            System.err.println("Error parsing arguments: " + ex.getMessage()
58                               + "\n");
59            Arguments.usage();
60            System.exit(1);
61        }
62
63        if (arg.isShowUsage()) {
64            Arguments.usage();
65            System.exit(1);
66        }
67
68        ProcessArgumentMatcher ap = null;
69        try {
70            ap = new ProcessArgumentMatcher(arg.getProcessString());
71        } catch (IllegalArgumentException iae) {
72            System.err.println("Invalid pid '" + arg.getProcessString()  + "' specified");
73            System.exit(1);
74        }
75
76        if (arg.isListProcesses()) {
77            for (VirtualMachineDescriptor vmd : ap.getVirtualMachineDescriptors(/* include jcmd in listing */)) {
78                System.out.println(vmd.id() + " " + vmd.displayName());
79            }
80            System.exit(0);
81        }
82
83        Collection<String> pids = ap.getVirtualMachinePids(JCmd.class);
84
85        if (pids.isEmpty()) {
86            System.err.println("Could not find any processes matching : '"
87                               + arg.getProcessString() + "'");
88            System.exit(1);
89        }
90
91        boolean success = true;
92        for (String pid : pids) {
93            System.out.println(pid + ":");
94            if (arg.isListCounters()) {
95                listCounters(pid);
96            } else {
97                try {
98                    executeCommandForPid(pid, arg.getCommand());
99                } catch(AttachOperationFailedException ex) {
100                    System.err.println(ex.getMessage());
101                    success = false;
102                } catch(Exception ex) {
103                    ex.printStackTrace();
104                    success = false;
105                }
106            }
107        }
108        System.exit(success ? 0 : 1);
109    }
110
111    private static void executeCommandForPid(String pid, String command)
112        throws AttachNotSupportedException, IOException,
113               UnsupportedEncodingException {
114        VirtualMachine vm = VirtualMachine.attach(pid);
115
116        // Cast to HotSpotVirtualMachine as this is an
117        // implementation specific method.
118        HotSpotVirtualMachine hvm = (HotSpotVirtualMachine) vm;
119        String lines[] = command.split("\\n");
120        for (String line : lines) {
121            if (line.trim().equals("stop")) {
122                break;
123            }
124            try (InputStream in = hvm.executeJCmd(line);) {
125                // read to EOF and just print output
126                byte b[] = new byte[256];
127                int n;
128                boolean messagePrinted = false;
129                do {
130                    n = in.read(b);
131                    if (n > 0) {
132                        String s = new String(b, 0, n, "UTF-8");
133                        System.out.print(s);
134                        messagePrinted = true;
135                    }
136                } while (n > 0);
137                if (!messagePrinted) {
138                    System.out.println("Command executed successfully");
139                }
140            }
141        }
142        vm.detach();
143    }
144
145    private static void listCounters(String pid) {
146        // Code from JStat (can't call it directly since it does System.exit)
147        VmIdentifier vmId = null;
148        try {
149            vmId = new VmIdentifier(pid);
150        } catch (URISyntaxException e) {
151            System.err.println("Malformed VM Identifier: " + pid);
152            return;
153        }
154        try {
155            MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId);
156            MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, -1);
157            JStatLogger logger = new JStatLogger(monitoredVm);
158            logger.printSnapShot("\\w*", // all names
159                    new AscendingMonitorComparator(), // comparator
160                    false, // not verbose
161                    true, // show unsupported
162                    System.out);
163            monitoredHost.detach(monitoredVm);
164        } catch (MonitorException ex) {
165            ex.printStackTrace();
166        }
167    }
168
169    /**
170     * Class to compare two Monitor objects by name in ascending order.
171     * (from jstat)
172     */
173    static class AscendingMonitorComparator implements Comparator<Monitor> {
174
175        public int compare(Monitor m1, Monitor m2) {
176            String name1 = m1.getName();
177            String name2 = m2.getName();
178            return name1.compareTo(name2);
179        }
180    }
181}
182