// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.actions;
import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.swing.JScrollPane;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.Preferences.Setting;
import org.openstreetmap.josm.data.Version;
import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.DatasetConsistencyTest;
import org.openstreetmap.josm.gui.ExtendedDialog;
import org.openstreetmap.josm.gui.widgets.JosmTextArea;
import org.openstreetmap.josm.plugins.PluginHandler;
import org.openstreetmap.josm.tools.BugReportExceptionHandler;
import org.openstreetmap.josm.tools.OpenBrowser;
import org.openstreetmap.josm.tools.PlatformHookUnixoid;
import org.openstreetmap.josm.tools.Shortcut;
import org.openstreetmap.josm.tools.Utils;
/**
* @author xeen
*
* Opens a dialog with useful status information like version numbers for Java, JOSM and plugins
* Also includes preferences with stripped username and password
*/
public final class ShowStatusReportAction extends JosmAction {
/**
* Constructs a new {@code ShowStatusReportAction}
*/
public ShowStatusReportAction() {
super(
tr("Show Status Report"),
"clock",
tr("Show status report with useful information that can be attached to bugs"),
Shortcut.registerShortcut("help:showstatusreport", tr("Help: {0}",
tr("Show Status Report")), KeyEvent.CHAR_UNDEFINED, Shortcut.NONE), false);
putValue("help", ht("/Action/ShowStatusReport"));
putValue("toolbar", "help/showstatusreport");
Main.toolbar.register(this);
}
private static void shortenParam(ListIterator<String> it, String[] param, String source, String target) {
if (source != null && target.length() < source.length() && param[1].startsWith(source)) {
it.set(param[0] + "=" + param[1].replace(source, target));
}
}
/**
* Replies the report header (software and system info)
* @return The report header (software and system info)
*/
public static String getReportHeader() {
StringBuilder text = new StringBuilder();
text.append(Version.getInstance().getReleaseAttributes());
text.append("\n");
text.append("Identification: " + Version.getInstance().getAgentString());
text.append("\n");
text.append("Memory Usage: ");
text.append(Runtime.getRuntime().totalMemory()/1024/1024);
text.append(" MB / ");
text.append(Runtime.getRuntime().maxMemory()/1024/1024);
text.append(" MB (");
text.append(Runtime.getRuntime().freeMemory()/1024/1024);
text.append(" MB allocated, but free)");
text.append("\n");
text.append("Java version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + ", " + System.getProperty("java.vm.name"));
text.append("\n");
if (Main.platform.getClass() == PlatformHookUnixoid.class) {
// Add Java package details
String packageDetails = ((PlatformHookUnixoid) Main.platform).getJavaPackageDetails();
if (packageDetails != null) {
text.append("Java package: ");
text.append(packageDetails);
text.append("\n");
}
// Add WebStart package details if run from JNLP
if (Package.getPackage("javax.jnlp") != null) {
String webStartDetails = ((PlatformHookUnixoid) Main.platform).getWebStartPackageDetails();
if (webStartDetails != null) {
text.append("WebStart package: ");
text.append(webStartDetails);
text.append("\n");
}
}
}
try {
final String envJavaHome = System.getenv("JAVA_HOME");
final String envJavaHomeAlt = Main.isPlatformWindows() ? "%JAVA_HOME%" : "${JAVA_HOME}";
final String propJavaHome = System.getProperty("java.home");
final String propJavaHomeAlt = "<java.home>";
// Build a new list of VM parameters to modify it below if needed (default implementation returns an UnmodifiableList instance)
List<String> vmArguments = new ArrayList<>(ManagementFactory.getRuntimeMXBean().getInputArguments());
for (ListIterator<String> it = vmArguments.listIterator(); it.hasNext(); ) {
String value = it.next();
if (value.contains("=")) {
String[] param = value.split("=");
// Hide some parameters for privacy concerns
if (param[0].toLowerCase().startsWith("-dproxy")) {
it.set(param[0]+"=xxx");
// Shorten some parameters for readability concerns
} else {
shortenParam(it, param, envJavaHome, envJavaHomeAlt);
shortenParam(it, param, propJavaHome, propJavaHomeAlt);
}
}
}
if (!vmArguments.isEmpty()) {
text.append("VM arguments: "+ vmArguments.toString().replace("\\\\", "\\"));
text.append("\n");
}
} catch (SecurityException e) {
// Ignore exception
}
if (Main.commandLineArgs.length > 0) {
text.append("Program arguments: "+ Arrays.toString(Main.commandLineArgs));
text.append("\n");
}
if (Main.main != null) {
DataSet dataset = Main.main.getCurrentDataSet();
if (dataset != null) {
String result = DatasetConsistencyTest.runTests(dataset);
if (result.length() == 0) {
text.append("Dataset consistency test: No problems found\n");
} else {
text.append("\nDataset consistency test:\n"+result+"\n");
}
}
}
text.append("\n");
text.append(PluginHandler.getBugReportText());
text.append("\n");
return text.toString();
}
@Override
public void actionPerformed(ActionEvent e) {
StringBuilder text = new StringBuilder();
String reportHeader = getReportHeader();
text.append(reportHeader);
try {
Map<String, Setting<?>> settings = Main.pref.getAllSettings();
Set<String> keys = new HashSet<>(settings.keySet());
for (String key : keys) {
// Remove sensitive information from status report
if (key.startsWith("marker.show") || key.contains("username") || key.contains("password") || key.contains("access-token")) {
settings.remove(key);
}
}
for (Entry<String, Setting<?>> entry : settings.entrySet()) {
text.append(entry.getKey()).append("=").append(entry.getValue().getValue().toString()).append("\n");
}
} catch (Exception x) {
Main.error(x);
}
JosmTextArea ta = new JosmTextArea(text.toString());
ta.setWrapStyleWord(true);
ta.setLineWrap(true);
ta.setEditable(false);
JScrollPane sp = new JScrollPane(ta);
ExtendedDialog ed = new ExtendedDialog(Main.parent,
tr("Status Report"),
new String[] {tr("Copy to clipboard and close"), tr("Report bug"), tr("Close") });
ed.setButtonIcons(new String[] {"copy.png", "bug.png", "cancel.png" });
ed.setContent(sp, false);
ed.setMinimumSize(new Dimension(380, 200));
ed.setPreferredSize(new Dimension(700, Main.parent.getHeight()-50));
switch (ed.showDialog().getValue()) {
case 1: Utils.copyToClipboard(text.toString()); break;
case 2: OpenBrowser.displayUrl(BugReportExceptionHandler.getBugReportUrl(
Utils.strip(reportHeader)).toExternalForm()) ; break;
}
}
}