001    /*
002     * This file is part of McIDAS-V
003     *
004     * Copyright 2007-2013
005     * Space Science and Engineering Center (SSEC)
006     * University of Wisconsin - Madison
007     * 1225 W. Dayton Street, Madison, WI 53706, USA
008     * https://www.ssec.wisc.edu/mcidas
009     * 
010     * All Rights Reserved
011     * 
012     * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013     * some McIDAS-V source code is based on IDV and VisAD source code.  
014     * 
015     * McIDAS-V is free software; you can redistribute it and/or modify
016     * it under the terms of the GNU Lesser Public License as published by
017     * the Free Software Foundation; either version 3 of the License, or
018     * (at your option) any later version.
019     * 
020     * McIDAS-V is distributed in the hope that it will be useful,
021     * but WITHOUT ANY WARRANTY; without even the implied warranty of
022     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023     * GNU Lesser Public License for more details.
024     * 
025     * You should have received a copy of the GNU Lesser Public License
026     * along with this program.  If not, see http://www.gnu.org/licenses.
027     */
028    
029    package edu.wisc.ssec.mcidasv;
030    
031    import ucar.unidata.idv.IntegratedDataViewer;
032    import ucar.unidata.util.HttpServer;
033    import ucar.unidata.util.LogUtil;
034    
035    import java.util.Hashtable;
036    
037    
038    import java.net.InetAddress;
039    import java.net.Socket;
040    
041    
042    
043    /**
044     * This provides http based access to a stack trace and enables the user to shut down McIDAS-V.
045     * This only is responsive to incoming requests from localhost
046     * the urls this provides are:
047     * http://localhost:<port>/stack.html
048     * http://localhost:<port>/info.html
049     * http://localhost:<port>/shutdown.html
050     *
051     * @author IDV development team
052     */
053    public class McIDASVMonitor extends HttpServer {
054    
055        private IntegratedDataViewer idv;
056    
057        /** The localhost */
058        private InetAddress localHost;
059    
060        public McIDASVMonitor(IntegratedDataViewer idv, int port) {
061            super(port);
062            this.idv = idv;
063        }
064    
065        /**
066         * Make the handler for this request. Check if the client is coming from localhost
067         * if not then return null.
068         *
069         * @param socket incoming socket
070         * @return handler or null
071         */
072        protected RequestHandler doMakeRequestHandler(Socket socket)
073                throws Exception {
074            if (localHost == null) {
075                localHost = InetAddress.getLocalHost();
076            }
077            InetAddress inet = socket.getInetAddress();
078            if (! (inet.getHostAddress().equals("127.0.0.1") || inet.getHostName().equals("localhost"))) {
079                return null;
080            }
081            return new MonitorRequestHandler(idv, this, socket);
082        }
083    
084        /**
085         * Class OneInstanceRequestHandler the handler
086         *
087         *
088         * @author IDV Development Team
089         * @version $Revision$
090         */
091        public class MonitorRequestHandler extends HttpServer.RequestHandler {
092    
093            /** The idv */
094            IntegratedDataViewer idv;
095            
096            /** The socket */
097            Socket mysocket;
098    
099            /**
100             * ctor
101             *
102             * @param idv the idv
103             * @param server the server
104             * @param socket the socket we handle the connection of
105             *
106             * @throws Exception On badness
107             */
108            public MonitorRequestHandler(IntegratedDataViewer idv,
109                                             HttpServer server, Socket socket)
110                    throws Exception {
111                super(server, socket);
112                this.idv = idv;
113                this.mysocket = socket;
114            }
115    
116            /**
117             * Try to trap the case where the socket doesn't contain any bytes
118             * This can happen when mcservl connects to ping
119             * Prevents an infinite loop in HttpServer
120             */
121            public void run() {
122                try {
123                    int availableBytes = mysocket.getInputStream().available();
124                    if (availableBytes != 0) {
125                            super.run();
126                    }
127                    mysocket.close();
128                } catch (Exception e) {
129                    System.err.println("HTTP server error");
130                }
131            }
132            
133            private void decorateHtml(StringBuffer sb) throws Exception {
134                String header = "<h1>McIDAS-V HTTP monitor</h1><hr>" +
135                    "<a href=stack.html>Stack Trace</a>&nbsp;|&nbsp;" +
136                    "<a href=info.html>System Information</a>&nbsp;|&nbsp;" +
137                    "<a href=shutdown.html>Shut Down</a><hr>";
138                writeResult(true,  header+sb.toString(),"text/html");
139            }
140    
141            /**
142             *
143             * @param path url path. ignored.
144             * @param formArgs form args
145             * @param httpArgs http args
146             * @param content content. unused.
147             *
148             * @throws Exception On badness
149             */
150            protected void handleRequest(String path, Hashtable formArgs,
151                                         Hashtable httpArgs, String content)
152                    throws Exception {
153                    if (path.equals("/stack.html")) {
154                            StringBuffer stack = LogUtil.getStackDump(true);
155                            decorateHtml(stack);
156                    }
157                    else if (path.equals("/info.html")) {
158                            StringBuffer extra   = idv.getIdvUIManager().getSystemInfo();
159                            extra.append("<H3>Data Sources</H3>");
160                            extra.append("<div style=\"margin-left:20px;\">");
161                            extra.append(idv.getDataManager().getDataSourceHtml());
162                            extra.append("</div>");
163                            extra.append(idv.getPluginManager().getPluginHtml());
164                            extra.append(idv.getResourceManager().getHtmlView());
165                            decorateHtml(extra);
166                    }
167                    else if (path.equals("/shutdown.html")) {
168                            decorateHtml(new StringBuffer("<a href=\"reallyshutdown.html\">Shut down McIDAS-V</a>"));
169                    }
170                    else if (path.equals("/reallyshutdown.html")) {
171                            writeResult(true, "McIDAS-V is shutting down","text/html");
172                            System.exit(0);
173                    }
174                    else if (path.equals("/") || path.equals("/index.html")) {
175                            decorateHtml(new StringBuffer(""));
176                    }
177                    else {
178                            decorateHtml(new StringBuffer("Unknown url:" + path));
179                    }
180            }
181        }
182    
183    }