001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2017 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 029package edu.wisc.ssec.mcidasv; 030 031import java.net.InetAddress; 032import java.net.Socket; 033 034import java.util.Hashtable; 035 036import ucar.unidata.idv.IntegratedDataViewer; 037import ucar.unidata.util.HttpServer; 038import ucar.unidata.util.LogUtil; 039 040import ch.qos.logback.classic.Level; 041import ch.qos.logback.classic.Logger; 042 043import org.slf4j.LoggerFactory; 044 045import edu.wisc.ssec.mcidasv.jython.Console; 046 047/** 048 * This provides http based access to a stack trace and enables the user to 049 * shut down McIDAS-V. 050 * 051 * This only is responsive to incoming requests from localhost. 052 * The only URLs available are the following: 053 * 054 * http://localhost:<port>/stack.html 055 * http://localhost:<port>/info.html 056 * http://localhost:<port>/shutdown.html 057 */ 058public class McIDASVMonitor extends HttpServer { 059 060 private IntegratedDataViewer idv; 061 062 /** The localhost */ 063 private InetAddress localHost; 064 065 public McIDASVMonitor(IntegratedDataViewer idv, int port) { 066 super(port); 067 this.idv = idv; 068 } 069 070 /** 071 * Make the handler for this request. Check if the client is coming from 072 * localhost, if not then return null. 073 * 074 * @param socket Incoming socket. 075 * @return handler or {@code null}. 076 */ 077 protected RequestHandler doMakeRequestHandler(Socket socket) 078 throws Exception { 079 if (localHost == null) { 080 localHost = InetAddress.getLocalHost(); 081 } 082 InetAddress inet = socket.getInetAddress(); 083 if (! (inet.getHostAddress().equals("127.0.0.1") || 084 inet.getHostName().equals("localhost"))) 085 { 086 return null; 087 } 088 return new MonitorRequestHandler(idv, this, socket); 089 } 090 091 public class MonitorRequestHandler extends HttpServer.RequestHandler { 092 093 IntegratedDataViewer idv; 094 095 Socket mysocket; 096 097 /** 098 * ctor 099 * 100 * @param idv the idv 101 * @param server the server 102 * @param socket the socket we handle the connection of 103 * 104 * @throws Exception On badness 105 */ 106 public MonitorRequestHandler(IntegratedDataViewer idv, 107 HttpServer server, Socket socket) 108 throws Exception 109 { 110 super(server, socket); 111 this.idv = idv; 112 this.mysocket = socket; 113 } 114 115 /** 116 * Try to trap the case where the socket doesn't contain any bytes 117 * This can happen when mcservl connects to ping 118 * Prevents an infinite loop in HttpServer 119 */ 120 public void run() { 121 try { 122 int availableBytes = mysocket.getInputStream().available(); 123 if (availableBytes != 0) { 124 super.run(); 125 } 126 mysocket.close(); 127 } catch (Exception e) { 128 System.err.println("HTTP server error"); 129 } 130 } 131 132 private void decorateHtml(StringBuffer sb) throws Exception { 133 String header = "<h1>McIDAS-V HTTP monitor</h1><hr>" + 134 "<a href=stack.html>Stack Trace</a> | " + 135 "<a href=info.html>System Information</a> | " + 136 "<a href=shutdown.html>Shut Down</a> | " + 137 "<a href=jython.html>Jython</a> | " + 138 "<a href=trace.html>Enable TRACE logging</a><hr>"; 139 writeResult(true, header+sb.toString(), "text/html"); 140 } 141 142 /** 143 * 144 * @param path url path. ignored. 145 * @param formArgs form args 146 * @param httpArgs http args 147 * @param content content. unused. 148 * 149 * @throws Exception On badness 150 */ 151 protected void handleRequest(String path, Hashtable formArgs, 152 Hashtable httpArgs, String content) 153 throws Exception 154 { 155 if (path.equals("/stack.html")) { 156 StringBuffer stack = LogUtil.getStackDump(true); 157 decorateHtml(stack); 158 } else if (path.equals("/info.html")) { 159 StringBuffer extra = idv.getIdvUIManager().getSystemInfo(); 160 extra.append("<H3>Data Sources</H3>"); 161 extra.append("<div style=\"margin-left:20px;\">"); 162 extra.append(idv.getDataManager().getDataSourceHtml()); 163 extra.append("</div>"); 164 extra.append(idv.getPluginManager().getPluginHtml()); 165 extra.append(idv.getResourceManager().getHtmlView()); 166 decorateHtml(extra); 167 } else if (path.equals("/shutdown.html")) { 168 decorateHtml(new StringBuffer("<a href=\"reallyshutdown.html\">Shut down McIDAS-V</a>")); 169 } else if (path.equals("/reallyshutdown.html")) { 170 writeResult(true, "McIDAS-V is shutting down","text/html"); 171 System.exit(0); 172 } else if (path.equals("/jython.html")) { 173 StringBuffer extra = new StringBuffer("Try to show <a href=shell.html>Jython Shell</a> in your McV session.<br/><br/>"); 174 extra.append("Try to <a href=console.html>show alternative Jython console</a><br/>"); 175 extra.append("If the event dispatch queue is not functioning, the console will probably not appear."); 176 decorateHtml(extra); 177 } else if (path.equals("/shell.html")) { 178 StringBuffer extra = new StringBuffer("Try to show Jython Shell in your McV session.<br/><br/>"); 179 extra.append("Try to <a href=console.html>show alternative Jython console</a><br/>"); 180 extra.append("If the event dispatch queue is not functioning, the console will probably not appear."); 181 decorateHtml(extra); 182 McIDASV.getStaticMcv().getJythonManager().createShell(); 183 } else if (path.equals("/trace.html")) { 184 enableTraceLogging(); 185 } else if (path.equals("/console.html")) { 186 StringBuffer extra = new StringBuffer("Try to show <a href=shell.html>Jython Shell</a> in your McV session.<br/><br/>"); 187 extra.append("Try to show alternative Jython console</a><br/>"); 188 extra.append("If the event dispatch queue is not functioning, the console will probably not appear."); 189 decorateHtml(extra); 190 Console.testConsole(false); 191 } else if (path.equals("/") || path.equals("/index.html")) { 192 decorateHtml(new StringBuffer("")); 193 } else { 194 decorateHtml(new StringBuffer("Unknown url:" + path)); 195 } 196 } 197 198 private void enableTraceLogging() throws Exception { 199 Logger rootLogger = (Logger)LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); 200 Level currentRootLevel = rootLogger.getLevel(); 201 Level currentEffectiveLevel = rootLogger.getEffectiveLevel(); 202 rootLogger.setLevel(Level.TRACE); 203 StringBuffer extra = new StringBuffer(512); 204 extra.append("Logging level set to TRACE<br/><br/>") 205 .append("Previous level: ").append(currentRootLevel).append("<br/>") 206 .append("Previous <i>effective</i> level: ").append(currentEffectiveLevel).append("<br/>"); 207 decorateHtml(extra); 208 } 209 } 210}