001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.actions;
003
004import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
005import static org.openstreetmap.josm.tools.I18n.tr;
006
007import java.awt.Dimension;
008import java.awt.event.ActionEvent;
009import java.awt.event.KeyEvent;
010import java.lang.management.ManagementFactory;
011import java.util.ArrayList;
012import java.util.Arrays;
013import java.util.HashSet;
014import java.util.List;
015import java.util.ListIterator;
016import java.util.Map;
017import java.util.Map.Entry;
018import java.util.Set;
019
020import javax.swing.JScrollPane;
021
022import org.openstreetmap.josm.Main;
023import org.openstreetmap.josm.data.Preferences.Setting;
024import org.openstreetmap.josm.data.Version;
025import org.openstreetmap.josm.data.osm.DataSet;
026import org.openstreetmap.josm.data.osm.DatasetConsistencyTest;
027import org.openstreetmap.josm.gui.ExtendedDialog;
028import org.openstreetmap.josm.gui.widgets.JosmTextArea;
029import org.openstreetmap.josm.plugins.PluginHandler;
030import org.openstreetmap.josm.tools.BugReportExceptionHandler;
031import org.openstreetmap.josm.tools.OpenBrowser;
032import org.openstreetmap.josm.tools.PlatformHookUnixoid;
033import org.openstreetmap.josm.tools.PlatformHookWindows;
034import org.openstreetmap.josm.tools.Shortcut;
035import org.openstreetmap.josm.tools.Utils;
036
037/**
038 * @author xeen
039 *
040 * Opens a dialog with useful status information like version numbers for Java, JOSM and plugins
041 * Also includes preferences with stripped username and password
042 */
043public final class ShowStatusReportAction extends JosmAction {
044
045    /**
046     * Constructs a new {@code ShowStatusReportAction}
047     */
048    public ShowStatusReportAction() {
049        super(
050                tr("Show Status Report"),
051                "clock",
052                tr("Show status report with useful information that can be attached to bugs"),
053                Shortcut.registerShortcut("help:showstatusreport", tr("Help: {0}",
054                        tr("Show Status Report")), KeyEvent.CHAR_UNDEFINED, Shortcut.NONE), false);
055
056        putValue("help", ht("/Action/ShowStatusReport"));
057        putValue("toolbar", "help/showstatusreport");
058        Main.toolbar.register(this);
059    }
060
061    private static void shortenParam(ListIterator<String> it, String[] param, String source, String target) {
062        if (source != null && target.length() < source.length() && param[1].startsWith(source)) {
063            it.set(param[0] + "=" + param[1].replace(source, target));
064        }
065    }
066
067    /**
068     * Replies the report header (software and system info)
069     * @return The report header (software and system info)
070     */
071    public static String getReportHeader()
072    {
073        StringBuilder text = new StringBuilder();
074        text.append(Version.getInstance().getReleaseAttributes());
075        text.append("\n");
076        text.append("Identification: " + Version.getInstance().getAgentString());
077        text.append("\n");
078        text.append("Memory Usage: ");
079        text.append(Runtime.getRuntime().totalMemory()/1024/1024);
080        text.append(" MB / ");
081        text.append(Runtime.getRuntime().maxMemory()/1024/1024);
082        text.append(" MB (");
083        text.append(Runtime.getRuntime().freeMemory()/1024/1024);
084        text.append(" MB allocated, but free)");
085        text.append("\n");
086        text.append("Java version: " + System.getProperty("java.version") + ", " + System.getProperty("java.vendor") + ", " + System.getProperty("java.vm.name"));
087        text.append("\n");
088        if (Main.platform.getClass() == PlatformHookUnixoid.class) {
089            String packageDetails = ((PlatformHookUnixoid) Main.platform).getJavaPackageDetails();
090            if (packageDetails != null) {
091                text.append("Java package: ");
092                text.append(packageDetails);
093                text.append("\n");
094            }
095        }
096        try {
097            final String env_java_home = System.getenv("JAVA_HOME");
098            final String env_java_home_alt = Main.platform instanceof PlatformHookWindows ? "%JAVA_HOME%" : "${JAVA_HOME}";
099            final String prop_java_home = System.getProperty("java.home");
100            final String prop_java_home_alt = "<java.home>";
101            // Build a new list of VM parameters to modify it below if needed (default implementation returns an UnmodifiableList instance)
102            List<String> vmArguments = new ArrayList<String>(ManagementFactory.getRuntimeMXBean().getInputArguments());
103            for (ListIterator<String> it = vmArguments.listIterator(); it.hasNext(); ) {
104                String value = it.next();
105                if (value.contains("=")) {
106                    String[] param = value.split("=");
107                    // Hide some parameters for privacy concerns
108                    if (param[0].toLowerCase().startsWith("-dproxy")) {
109                        it.set(param[0]+"=xxx");
110                    // Shorten some parameters for readability concerns
111                    } else {
112                        shortenParam(it, param, env_java_home, env_java_home_alt);
113                        shortenParam(it, param, prop_java_home, prop_java_home_alt);
114                    }
115                }
116            }
117            if (!vmArguments.isEmpty()) {
118                text.append("VM arguments: "+ vmArguments.toString().replace("\\\\", "\\"));
119                text.append("\n");
120            }
121        } catch (SecurityException e) {
122            // Ignore exception
123        }
124        if (Main.commandLineArgs.length > 0) {
125            text.append("Program arguments: "+ Arrays.toString(Main.commandLineArgs));
126            text.append("\n");
127        }
128        if (Main.main != null) {
129            DataSet dataset = Main.main.getCurrentDataSet();
130            if (dataset != null) {
131                String result = DatasetConsistencyTest.runTests(dataset);
132                if (result.length() == 0) {
133                    text.append("Dataset consistency test: No problems found\n");
134                } else {
135                    text.append("\nDataset consistency test:\n"+result+"\n");
136                }
137            }
138        }
139        text.append("\n");
140        text.append(PluginHandler.getBugReportText());
141        text.append("\n");
142
143        return text.toString();
144    }
145
146    @Override
147    public void actionPerformed(ActionEvent e) {
148        StringBuilder text = new StringBuilder();
149        String reportHeader = getReportHeader();
150        text.append(reportHeader);
151        try {
152            Map<String, Setting> settings = Main.pref.getAllSettings();
153            settings.remove("osm-server.username");
154            settings.remove("osm-server.password");
155            settings.remove("oauth.access-token.key");
156            settings.remove("oauth.access-token.secret");
157            Set<String> keys = new HashSet<String>(settings.keySet());
158            for (String key : keys) {
159                if (key.startsWith("marker.show")) {
160                    settings.remove(key);
161                }
162            }
163            for (Entry<String, Setting> entry : settings.entrySet()) {
164                text.append(entry.getKey()).append("=").append(entry.getValue().getValue().toString()).append("\n");
165            }
166        } catch (Exception x) {
167            x.printStackTrace();
168        }
169
170        JosmTextArea ta = new JosmTextArea(text.toString());
171        ta.setWrapStyleWord(true);
172        ta.setLineWrap(true);
173        ta.setEditable(false);
174        JScrollPane sp = new JScrollPane(ta);
175
176        ExtendedDialog ed = new ExtendedDialog(Main.parent,
177                tr("Status Report"),
178                new String[] {tr("Copy to clipboard and close"), tr("Report bug"), tr("Close") });
179        ed.setButtonIcons(new String[] {"copy.png", "bug.png", "cancel.png" });
180        ed.setContent(sp, false);
181        ed.setMinimumSize(new Dimension(380, 200));
182        ed.setPreferredSize(new Dimension(700, Main.parent.getHeight()-50));
183
184        switch (ed.showDialog().getValue()) {
185            case 1: Utils.copyToClipboard(text.toString()); break;
186            case 2: OpenBrowser.displayUrl(BugReportExceptionHandler.getBugReportUrl(
187                        Utils.strip(reportHeader)).toExternalForm()) ; break;
188        }
189    }
190}