001package jmri.jmrit.mailreport;
002
003import java.awt.*;
004import java.io.File;
005import java.net.InetAddress;
006import java.net.NetworkInterface;
007import java.net.SocketException;
008import java.util.Collection;
009import java.util.Enumeration;
010
011import javax.swing.JFrame;
012
013import jmri.util.gui.GuiLafPreferencesManager;
014import jmri.InstanceManager;
015import jmri.jmrix.ConnectionConfig;
016import jmri.jmrix.ConnectionConfigManager;
017import jmri.profile.Profile;
018import jmri.profile.ProfileManager;
019import jmri.util.FileUtil;
020import jmri.util.JmriInsets;
021import jmri.util.JmriJFrame;
022import jmri.util.PortNameMapper;
023import jmri.util.PortNameMapper.SerialPortFriendlyName;
024import jmri.util.zeroconf.ZeroConfService;
025import jmri.util.zeroconf.ZeroConfServiceManager;
026
027/**
028 * Provide the JMRI context info.
029 *
030 * @author Bob Jacobsen Copyright (C) 2007, 2009
031 * @author Matt Harris Copyright (C) 2008, 2009
032 */
033public class ReportContext {
034
035    String report = "";
036
037    /**
038     * Provide a report of the current JMRI context
039     *
040     * @param reportNetworkInfo true if network connection and zeroconf service
041     *                          information to be included
042     * @return current JMRI context
043     */
044    public String getReport(boolean reportNetworkInfo) {
045
046        addString("JMRI Version: " + jmri.Version.name() + "   ");
047
048        addEarlyInitializationPreferences();
049
050        addString("JMRI configuration file name: "
051                + System.getProperty("org.jmri.apps.Apps.configFilename") + "   (from org.jmri.apps.Apps.configFilename system property)");
052        if (!jmri.util.JmriJFrame.getFrameList().isEmpty() && jmri.util.JmriJFrame.getFrameList().get(0) != null) {
053            addString("JMRI main window name: "
054                    + jmri.util.JmriJFrame.getFrameList().get(0).getTitle() + "   ");
055        } else {
056            addString("No main window present");
057        }
058
059        addString("JMRI Application: " + jmri.Application.getApplicationName() + "   ");
060        ConnectionConfigManager cm = InstanceManager.getNullableDefault(ConnectionConfigManager.class);
061        if (cm != null) {
062            ConnectionConfig[] connList = cm.getConnections();
063            for (int x = 0; x < connList.length; x++) {
064                ConnectionConfig conn = connList[x];
065                addString("Connection " + x + ": " + conn.getManufacturer() + " connected via " + conn.name() + " on " + conn.getInfo() + " Disabled " + conn.getDisabled() + "   ");
066            }
067        } else {
068            addString("No connections present");
069        }
070        
071        addString("Available Communication Ports:");
072        addCommunicationPortInfo();
073
074        Profile profile = ProfileManager.getDefault().getActiveProfile();
075        if (profile != null) {
076            addString("Active profile: " + profile.getName() + "   ");
077            addString("Profile location: " + profile.getPath().getPath() + "   ");
078            addString("Profile ID: " + profile.getId() + "   ");
079        } else {
080            addString("No active profile");
081        }
082        
083        addString("JMRI Network ID: " + jmri.util.node.NodeIdentity.networkIdentity());
084        addString("JMRI Storage ID: " + jmri.util.node.NodeIdentity.storageIdentity(profile));
085
086        String prefs = FileUtil.getUserFilesPath();
087        addString("Preferences directory: " + prefs + "   ");
088
089        String prog = System.getProperty("user.dir");
090        addString("Program directory: " + prog + "   ");
091
092        String roster = jmri.jmrit.roster.Roster.getDefault().getRosterIndexPath();
093        addString("Roster index location: " + roster + "   ");
094
095        File panel = jmri.configurexml.LoadXmlUserAction.getCurrentFile();
096        addString("Current panel file: " + (panel == null ? "[none]" : panel.getPath()) + "   ");
097        
098        addString("Locale: " + InstanceManager.getDefault(GuiLafPreferencesManager.class).getLocale());
099
100        //String operations = jmri.jmrit.operations.setup.OperationsSetupXml.getFileLocation();
101        //addString("Operations files location: "+operations+"  ");
102        jmri.AudioManager am = jmri.InstanceManager.getNullableDefault(jmri.AudioManager.class);
103        jmri.jmrit.audio.AudioFactory af = null;
104        if ( am !=null ) {
105            af = am.getActiveAudioFactory();
106        }
107        String audio = af != null ? af.toString() : "[not initialised]";
108        addString("Audio factory type: " + audio + "   ");
109
110        addProperty("java.version");
111        addProperty("java.vendor");
112        addProperty("java.home");
113
114        addProperty("java.vm.version");
115        addProperty("java.vm.vendor");
116        addProperty("java.vm.name");
117
118        addProperty("java.specification.version");
119        addProperty("java.specification.vendor");
120        addProperty("java.specification.name");
121
122        addProperty("java.class.version");
123        addProperty("java.class.path");
124        addProperty("java.library.path");
125
126        addProperty("java.compiler");
127        addProperty("java.ext.dirs");
128
129        addProperty("file.encoding");
130
131        addProperty("os.name");
132        addProperty("os.arch");
133        addProperty("os.version");
134
135        addProperty("python.home");
136        addProperty("python.path");
137        addProperty("python.cachedir");
138        addProperty("python.cachedir.skip");
139        addProperty("python.startup");
140
141        addProperty("user.name");
142        addProperty("user.home");
143        addProperty("user.dir");
144        addProperty("user.country");
145        addProperty("user.language");
146        addProperty("user.timezone");
147        addProperty("jmri.log.path");
148        
149        addString("FileSystemView#getDefaultDirectory(): "+javax.swing.filechooser.FileSystemView.getFileSystemView().getDefaultDirectory().getPath() );
150        addString("FileSystemView#getHomeDirectory(): "+javax.swing.filechooser.FileSystemView.getFileSystemView().getHomeDirectory().getPath() );
151        addString("Default JFileChooser(): "+(new javax.swing.JFileChooser()).getCurrentDirectory().getPath() );
152
153        addScreenSize();
154
155        if (reportNetworkInfo) {
156            addNetworkInfo();
157        }
158
159        return report;
160
161    }
162
163    void addString(String val) {
164        report = report + val + "\n";
165    }
166
167    void addProperty(String prop) {
168        addString(prop + ": " + System.getProperty(prop) + "   ");
169    }
170
171    void addEarlyInitializationPreferences() {
172        jmri.util.EarlyInitializationPreferences eip =
173                jmri.util.EarlyInitializationPreferences.getInstance();
174
175        for (String pref : eip.getStartupPreferences()) {
176            addString(pref + "   ");
177        }
178    }
179
180    /**
181     * Provide screen - size information. This is based on the
182     * jmri.util.JmriJFrame calculation, but isn't refactored to there because
183     * we also want diagnostic info
184     */
185    public void addScreenSize() {
186        try {
187            // Find screen size. This throws null-pointer exceptions on
188            // some Java installs, however, for unknown reasons, so be
189            // prepared to fall back.
190            JFrame dummy = new JFrame();
191            try {
192                Insets insets = dummy.getToolkit().getScreenInsets(dummy.getGraphicsConfiguration());
193                Dimension screen = dummy.getToolkit().getScreenSize();
194                addString("Screen size h:" + screen.height + ", w:" + screen.width + " Inset t:" + insets.top + ", b:" + insets.bottom
195                        + "; l:" + insets.left + ", r:" + insets.right);
196            } catch (NoSuchMethodError ex) {
197                Dimension screen = dummy.getToolkit().getScreenSize();
198                addString("Screen size h:" + screen.height + ", w:" + screen.width
199                        + " (No Inset method available)");
200            }
201        } catch (HeadlessException ex) {
202            // failed, fall back to standard method
203            addString("(Cannot sense screen size due to " + ex.toString() + ")");
204        }
205
206        try {
207            // Find screen resolution. Not expected to fail, but just in case....
208            int dpi = Toolkit.getDefaultToolkit().getScreenResolution();
209            addString("Screen resolution: " + dpi);
210        } catch (HeadlessException ex) {
211            addString("Screen resolution not available");
212        }
213
214        // look at context
215        try {
216            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
217            addString("Environment max bounds: " + ge.getMaximumWindowBounds());
218
219            try {
220                for (JmriJFrame.ScreenDimensions sd: JmriJFrame.getScreenDimensions()) {
221                    addString("Device: " + sd.getGraphicsDevice().getIDstring() + " bounds = " + sd.getBounds());
222                    addString("Device: " + sd.getGraphicsDevice().getIDstring() + " insets = " + sd.getInsets());
223                }
224            } catch (HeadlessException ex) {
225                addString("Exception getting device bounds " + ex.getMessage());
226            }
227        } catch (HeadlessException ex) {
228            addString("Exception getting max window bounds " + ex.getMessage());
229        }
230        // Return the insets using a custom class
231        // which should return the correct values under
232        // various Linux window managers
233        try {
234            Insets jmriInsets = JmriInsets.getInsets();
235            addString("JmriInsets t:" + jmriInsets.top + ", b:" + jmriInsets.bottom
236                    + "; l:" + jmriInsets.left + ", r:" + jmriInsets.right);
237        } catch (Exception ex) {
238            addString("Exception getting JmriInsets " + ex.getMessage());
239        }
240
241        var laf = javax.swing.UIManager.getLookAndFeel();
242        if ( laf !=null ) {
243            addString("Look and Feel: " + laf.getName());
244        } else {
245            addString("null LookAndFeel");
246        }
247
248    }
249
250    /**
251     * Add network connection and running service information
252     */
253    private void addNetworkInfo() {
254        try {
255            // This code is based on that in jmri.jmrit.withrottle.UserInterface which,
256            // itself, was adapted from http://www.rgagnon.com/javadetails/java-0390.html
257            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
258            while (networkInterfaces.hasMoreElements()) {
259                NetworkInterface networkInterface = networkInterfaces.nextElement();
260                Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
261                while (inetAddresses.hasMoreElements()) {
262                    InetAddress inetAddress = inetAddresses.nextElement();
263                    String hostAddress = inetAddress.getHostAddress();
264                    if (!hostAddress.equals("0.0.0.0") && !hostAddress.regionMatches(0, "127", 0, 3) && !hostAddress.contains(":")) {
265                        addString("Network Interface: " + networkInterface.getName());
266                        addString(" Long Name: " + networkInterface.getDisplayName());
267                        addString(" Host Name: " + inetAddress.getHostName());
268                        addString(" IP address: " + hostAddress);
269                    }
270                }
271            }
272        } catch (SocketException ex) {
273            addString("Unable to enumerate Network Interfaces");
274        }
275
276        Collection<ZeroConfService> services = InstanceManager.getDefault(ZeroConfServiceManager.class).allServices();
277        for (InetAddress address : InstanceManager.getDefault(ZeroConfServiceManager.class).getAddresses()) {
278            addString("ZeroConfService host: " + InstanceManager.getDefault(ZeroConfServiceManager.class).hostName(address) + " running " + services.size() + " service(s)");
279        }
280        if (!services.isEmpty()) {
281            for (ZeroConfService service : services) {
282                addString("ZeroConfService: " + service.getServiceInfo().getQualifiedName() + "  ");
283                addString(" Name: " + service.getName() + "   ");
284                try {
285                    for (String address : service.getServiceInfo().getHostAddresses()) {
286                        addString(" Address:" + address + "   ");
287                    }
288                } catch (NullPointerException ex) {
289                    addString(" Address: [unknown due to NPE]");
290                }
291                addString(" Port: " + service.getServiceInfo().getPort() + "   ");
292                addString(" Server: " + service.getServiceInfo().getServer() + "   ");
293                addString(" Type: " + service.getType() + "   ");
294                try {
295                    for (String url : service.getServiceInfo().getURLs()) {
296                        addString(" URL: " + url + "   ");
297                    }
298                } catch (NullPointerException ex) {
299                    addString(" URL: [unknown due to NPE]");
300                }
301                addString(" Published: " + (service.isPublished() ? "yes" : "no"));
302            }
303        }
304    }
305
306    /**
307     * Add communication port information
308     */
309    private void addCommunicationPortInfo() {
310        var portNames = jmri.jmrix.AbstractSerialPortController.getActualPortNames();
311
312        addString(String.format(" Found %s serial ports", portNames.size()));
313
314        // now output the details
315        for (String name : portNames) {
316            // output details
317            SerialPortFriendlyName port = PortNameMapper.getPortNameMap().get(name);
318            if (port == null) {
319                port = new SerialPortFriendlyName(name, null);
320                PortNameMapper.getPortNameMap().put(name, port);
321            }
322            addString(" Port: " + name);
323        }
324    }
325
326}
327
328