From 8027c95be96d7cac24eeec1e67a81ff80c8f2715 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 18 Aug 2012 08:45:54 +0800 Subject: [PATCH] StatView refactor --- .../druid/stat/DruidStatManagerFacade.java | 20 ++- .../druid/support/JSONDruidStatService.java | 68 +++++---- .../druid/support/http/StatViewServlet.java | 134 +++++++++++++----- .../java/com/alibaba/druid/util/IpUtils.java | 18 --- .../support/http/resources/index.html | 8 ++ .../support/http/resources/js/basicStat.js | 3 + .../http/StatViewServletTest_resetEnable.java | 79 +++++++++++ .../com/alibaba/druid/util/IpUtilsTest.java | 47 ------ 8 files changed, 248 insertions(+), 129 deletions(-) delete mode 100644 src/main/java/com/alibaba/druid/util/IpUtils.java create mode 100644 src/test/java/com/alibaba/druid/bvt/support/http/StatViewServletTest_resetEnable.java delete mode 100644 src/test/java/com/alibaba/druid/util/IpUtilsTest.java diff --git a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java index c84ba7d3d7..f94ea9be6e 100644 --- a/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java +++ b/src/main/java/com/alibaba/druid/stat/DruidStatManagerFacade.java @@ -8,6 +8,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicLong; import com.alibaba.druid.VERSION; import com.alibaba.druid.util.DruidDataSourceUtils; @@ -25,7 +26,9 @@ import com.alibaba.druid.util.JdbcSqlStatUtils; */ public class DruidStatManagerFacade { - private final static DruidStatManagerFacade instance = new DruidStatManagerFacade(); + private final static DruidStatManagerFacade instance = new DruidStatManagerFacade(); + private boolean resetEnable = true; + private final AtomicLong resetCount = new AtomicLong(); private DruidStatManagerFacade(){ } @@ -49,6 +52,15 @@ public class DruidStatManagerFacade { public void resetAll() { resetSqlStat(); resetDataSourceStat(); + resetCount.incrementAndGet(); + } + + public boolean isResetEnable() { + return resetEnable; + } + + public void setResetEnable(boolean resetEnable) { + this.resetEnable = resetEnable; } public Object getSqlStatById(Integer id) { @@ -129,9 +141,15 @@ public class DruidStatManagerFacade { Map dataMap = new LinkedHashMap(); dataMap.put("Version", VERSION.getVersionNumber()); dataMap.put("Drivers", getDriversData()); + dataMap.put("ResetEnable", isResetEnable()); + dataMap.put("ResetCount", getResetCount()); return dataMap; } + public long getResetCount() { + return resetCount.get(); + } + private List getDriversData() { List drivers = new ArrayList(); for (Enumeration e = DriverManager.getDrivers(); e.hasMoreElements();) { diff --git a/src/main/java/com/alibaba/druid/support/JSONDruidStatService.java b/src/main/java/com/alibaba/druid/support/JSONDruidStatService.java index 75fc2b05a2..f7114bf9da 100644 --- a/src/main/java/com/alibaba/druid/support/JSONDruidStatService.java +++ b/src/main/java/com/alibaba/druid/support/JSONDruidStatService.java @@ -27,7 +27,7 @@ public class JSONDruidStatService { private final static JSONDruidStatService instance = new JSONDruidStatService(); - private static DruidStatManagerFacade druidStatManager = DruidStatManagerFacade.getInstance(); + private static DruidStatManagerFacade statManagerFacade = DruidStatManagerFacade.getInstance(); public final static int RESULT_CODE_SUCCESS = 1; public final static int RESULT_CODE_ERROR = -1; @@ -44,35 +44,43 @@ public class JSONDruidStatService { return instance; } + public boolean isResetEnable() { + return statManagerFacade.isResetEnable(); + } + + public void setResetEnable(boolean value) { + statManagerFacade.setResetEnable(value); + } + public String service(String url) { Map parameters = StringUtils.getParameters(url); if (url.equals("/basic.json")) { - return returnJSONResult(RESULT_CODE_SUCCESS, druidStatManager.returnJSONBasicStat()); + return returnJSONResult(RESULT_CODE_SUCCESS, statManagerFacade.returnJSONBasicStat()); } if (url.equals("/reset-all.json")) { - druidStatManager.resetAll(); + statManagerFacade.resetAll(); SpringStatManager.getInstance().resetStat(); WebAppStatManager.getInstance().resetStat(); - + return returnJSONResult(RESULT_CODE_SUCCESS, null); } if (url.equals("/datasource.json")) { - return returnJSONResult(RESULT_CODE_SUCCESS, druidStatManager.getDataSourceStatList()); + return returnJSONResult(RESULT_CODE_SUCCESS, statManagerFacade.getDataSourceStatList()); } if (url.startsWith("/datasource-")) { Integer id = StringUtils.subStringToInteger(url, "datasource-", "."); - Object result = druidStatManager.getDataSourceStatData(id); + Object result = statManagerFacade.getDataSourceStatData(id); return returnJSONResult(result == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, result); } if (url.startsWith("/connectionInfo-") && url.endsWith(".json")) { Integer id = StringUtils.subStringToInteger(url, "connectionInfo-", "."); - List connectionInfoList = druidStatManager.getPoolingConnectionInfoByDataSourceId(id); + List connectionInfoList = statManagerFacade.getPoolingConnectionInfoByDataSourceId(id); return returnJSONResult(connectionInfoList == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, connectionInfoList); } @@ -90,38 +98,38 @@ public class JSONDruidStatService { Integer id = StringUtils.subStringToInteger(url, "sql-", ".json"); return returnJSONSqlInfo(id); } - + if (url.startsWith("/weburi.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, getWebURIStatDataList(parameters)); } - + if (url.startsWith("/websession.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, getWebSessionStatDataList(parameters)); } - + if (url.startsWith("/spring.json")) { return returnJSONResult(RESULT_CODE_SUCCESS, getSpringStatDataList(parameters)); } return returnJSONResult(RESULT_CODE_ERROR, "Do not support this request, please contact with administrator."); } - + private List> getSpringStatDataList(Map parameters) { List> array = SpringStatManager.getInstance().getMethodStatData(); - return comparatorOrderBy(array, parameters); + return comparatorOrderBy(array, parameters); } - + private List> getWebURIStatDataList(Map parameters) { List> array = WebAppStatManager.getInstance().getURIStatData(); - return comparatorOrderBy(array, parameters); + return comparatorOrderBy(array, parameters); } - + private List> getWebSessionStatDataList(Map parameters) { List> array = WebAppStatManager.getInstance().getSessionStatData(); return array; } - - private List> comparatorOrderBy(List> array,Map parameters){ + + private List> comparatorOrderBy(List> array, Map parameters) { // when open the stat page before executing some sql if (array == null || array.isEmpty()) return null; @@ -160,20 +168,20 @@ public class JSONDruidStatService { return array.subList(fromIndex, toIndex); } - + private List> getSqlStatDataList(Map parameters) { - List> array = druidStatManager.getSqlStatDataList(); + List> array = statManagerFacade.getSqlStatDataList(); return comparatorOrderBy(array, parameters); } private String returnJSONSqlInfo(Integer id) { - Map map = druidStatManager.getSqlStatData(id); + Map map = statManagerFacade.getSqlStatData(id); if (map == null) { - return returnJSONResult(RESULT_CODE_ERROR , null); + return returnJSONResult(RESULT_CODE_ERROR, null); } - map.put("formattedSql",SQLUtils.format((String) map.get("SQL"),(String) map.get("DbType"))); + map.put("formattedSql", SQLUtils.format((String) map.get("SQL"), (String) map.get("DbType"))); List statementList = SQLUtils.parseStatements((String) map.get("SQL"), (String) map.get("DbType")); - + if (!statementList.isEmpty()) { SQLStatement statemen = statementList.get(0); SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(statementList, (String) map.get("DbType")); @@ -184,17 +192,17 @@ public class JSONDruidStatService { map.put("parsedRelationships", visitor.getRelationships().toString()); map.put("parsedOrderbycolumns", visitor.getOrderByColumns().toString()); } - - DateFormat format = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS"); - Date maxTimespanOccurTime = (Date)map.get("MaxTimespanOccurTime"); - if (maxTimespanOccurTime != null) { - map.put("MaxTimespanOccurTime", format.format(maxTimespanOccurTime)); - } + + DateFormat format = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss:SSS"); + Date maxTimespanOccurTime = (Date) map.get("MaxTimespanOccurTime"); + if (maxTimespanOccurTime != null) { + map.put("MaxTimespanOccurTime", format.format(maxTimespanOccurTime)); + } return returnJSONResult(map == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, map); } private String returnJSONActiveConnectionStackTrace(Integer id) { - List result = druidStatManager.getActiveConnectionStackTraceByDataSourceId(id); + List result = statManagerFacade.getActiveConnectionStackTraceByDataSourceId(id); if (result == null) { return returnJSONResult(RESULT_CODE_ERROR, "require set removeAbandoned=true"); diff --git a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java index 96ee62c317..613bd36a08 100644 --- a/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java +++ b/src/main/java/com/alibaba/druid/support/http/StatViewServlet.java @@ -1,9 +1,8 @@ package com.alibaba.druid.support.http; -import com.alibaba.druid.util.IpUtils; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -11,6 +10,10 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.alibaba.druid.support.JSONDruidStatService; +import com.alibaba.druid.support.http.util.IPAddress; +import com.alibaba.druid.support.http.util.IPRange; +import com.alibaba.druid.support.logging.Log; +import com.alibaba.druid.support.logging.LogFactory; import com.alibaba.druid.util.IOUtils; /** @@ -20,43 +23,110 @@ import com.alibaba.druid.util.IOUtils; */ public class StatViewServlet extends HttpServlet { - /** - * - */ - private static final long serialVersionUID = 1L; + private final static Log LOG = LogFactory.getLog(StatViewServlet.class); - private final static String RESOURCE_PATH = "support/http/resources"; - private final static String TEMPLATE_PAGE_RESOURCE_PATH = RESOURCE_PATH + "/template.html"; + private static final long serialVersionUID = 1L; - private static JSONDruidStatService jsonDruidStatService = JSONDruidStatService.getInstance(); + public static final String PARAM_NAME_RESET_ENABLE = "resetEnable"; + public static final String PARAM_NAME_ALLOW = "allow"; + public static final String PARAM_NAME_DENY = "deny"; - public String templatePage; - + private final static String RESOURCE_PATH = "support/http/resources"; + private final static String TEMPLATE_PAGE_RESOURCE_PATH = RESOURCE_PATH + "/template.html"; - private String permittedIp; - private Pattern ipCheckPattern; + private JSONDruidStatService statService = JSONDruidStatService.getInstance(); + + public String templatePage; + + private List allowList = new ArrayList(); + private List denyList = new ArrayList(); public void init() throws ServletException { try { templatePage = IOUtils.readFromResource(TEMPLATE_PAGE_RESOURCE_PATH); - + } catch (IOException e) { throw new ServletException("error read templatePage:" + TEMPLATE_PAGE_RESOURCE_PATH, e); } - permittedIp = getServletConfig().getInitParameter("permittedIp"); - if (permittedIp != null ) { - this.ipCheckPattern = IpUtils.buildIpCheckPattern(permittedIp); + + try { + String param = getInitParameter(PARAM_NAME_RESET_ENABLE); + if (param != null && param.trim().length() != 0) { + param = param.trim(); + boolean resetEnable = Boolean.parseBoolean(param); + statService.setResetEnable(resetEnable); + } + } catch (Exception e) { + String msg = "initParameter config error, resetEnable : " + getInitParameter(PARAM_NAME_RESET_ENABLE); + LOG.error(msg, e); + } + + try { + String param = getInitParameter(PARAM_NAME_ALLOW); + if (param != null && param.trim().length() != 0) { + param = param.trim(); + String[] items = param.split(","); + + for (String item : items) { + if (item == null || item.length() == 0) { + continue; + } + + IPRange ipRange = new IPRange(item); + allowList.add(ipRange); + } + } + } catch (Exception e) { + String msg = "initParameter config error, allow : " + getInitParameter(PARAM_NAME_ALLOW); + LOG.error(msg, e); + } + + try { + String param = getInitParameter(PARAM_NAME_DENY); + if (param != null && param.trim().length() != 0) { + param = param.trim(); + String[] items = param.split(","); + + for (String item : items) { + if (item == null || item.length() == 0) { + continue; + } + + IPRange ipRange = new IPRange(item); + denyList.add(ipRange); + } + } + } catch (Exception e) { + String msg = "initParameter config error, deny : " + getInitParameter(PARAM_NAME_DENY); + LOG.error(msg, e); } } - private boolean isPermittedRequest(HttpServletRequest request) { - //if nothing is configured, every host can access the stat result(default) - if (permittedIp == null || permittedIp.trim().equals("")) { - return true; + public boolean isPermittedRequest(HttpServletRequest request) { + String remoteAddress = request.getRemoteAddr(); + return isPermittedRequest(remoteAddress); + } + + public boolean isPermittedRequest(String remoteAddress) { + IPAddress ipAddress = new IPAddress(remoteAddress); + + for (IPRange range : denyList) { + if (range.isIPAddressInRange(ipAddress)) { + return false; + } } - String remoteIp = request.getRemoteAddr(); - Matcher matcher = ipCheckPattern.matcher(remoteIp); - return matcher.matches(); + + if (allowList.size() > 0) { + for (IPRange range : allowList) { + if (range.isIPAddressInRange(ipAddress)) { + return true; + } + } + + return false; + } + + return true; } public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -66,8 +136,6 @@ public class StatViewServlet extends HttpServlet { response.setCharacterEncoding("utf-8"); - - if (contextPath == null) { // root context contextPath = ""; } @@ -79,7 +147,7 @@ public class StatViewServlet extends HttpServlet { returnResourceFile(path, uri, response); return; } - + if ("".equals(path)) { if (contextPath == null || contextPath.equals("") || contextPath.equals("/")) { response.sendRedirect("/druid/index.html"); @@ -99,18 +167,18 @@ public class StatViewServlet extends HttpServlet { if (request.getQueryString() != null && request.getQueryString().length() > 0) { fullUrl += "?" + request.getQueryString(); } - response.getWriter().print(jsonDruidStatService.service(fullUrl)); + response.getWriter().print(statService.service(fullUrl)); return; } - + // find file in resources path returnResourceFile(path, uri, response); } - - private void returnResourceFile(String fileName, String uri, HttpServletResponse response) throws ServletException, IOException { + private void returnResourceFile(String fileName, String uri, HttpServletResponse response) throws ServletException, + IOException { String text = IOUtils.readFromResource(RESOURCE_PATH + fileName); - if(text == null) { + if (text == null) { response.sendRedirect(uri + "/index.html"); return; } diff --git a/src/main/java/com/alibaba/druid/util/IpUtils.java b/src/main/java/com/alibaba/druid/util/IpUtils.java deleted file mode 100644 index 4b70ed5aac..0000000000 --- a/src/main/java/com/alibaba/druid/util/IpUtils.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.alibaba.druid.util; - -import java.util.regex.Pattern; - -public class IpUtils { - - public static Pattern buildIpCheckPattern(String permittedIP) { - String[] addrs = permittedIP.split(","); - StringBuilder sb = new StringBuilder(); - for (String addr : addrs ) { - addr = addr.trim(); - addr = addr.replace("*", "\\d{1,3}"); - sb.append(addr.trim()).append("|"); - } - return Pattern.compile(sb.toString()); - } - -} diff --git a/src/main/resources/support/http/resources/index.html b/src/main/resources/support/http/resources/index.html index 5a54b93f85..0ccd105efe 100644 --- a/src/main/resources/support/http/resources/index.html +++ b/src/main/resources/support/http/resources/index.html @@ -30,6 +30,14 @@ drivers + + ResetEnable + + + + ResetCount + + diff --git a/src/main/resources/support/http/resources/js/basicStat.js b/src/main/resources/support/http/resources/js/basicStat.js index 38cdfc288d..5fa288fb4e 100644 --- a/src/main/resources/support/http/resources/js/basicStat.js +++ b/src/main/resources/support/http/resources/js/basicStat.js @@ -20,4 +20,7 @@ function ajaxResponseForBasicInfo() { } document.getElementById("DruidDrivers").innerHTML = driverHtml; } + + document.getElementById("ResetEnable").innerHTML = jsonContent.ResetEnable; + document.getElementById("ResetCount").innerHTML = jsonContent.ResetCount; } diff --git a/src/test/java/com/alibaba/druid/bvt/support/http/StatViewServletTest_resetEnable.java b/src/test/java/com/alibaba/druid/bvt/support/http/StatViewServletTest_resetEnable.java new file mode 100644 index 0000000000..adb694bf7a --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/support/http/StatViewServletTest_resetEnable.java @@ -0,0 +1,79 @@ +package com.alibaba.druid.bvt.support.http; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.springframework.mock.web.MockServletConfig; + +import com.alibaba.druid.support.JSONDruidStatService; +import com.alibaba.druid.support.http.StatViewServlet; + +public class StatViewServletTest_resetEnable extends TestCase { + + protected void setUp() throws Exception { + JSONDruidStatService.getInstance().setResetEnable(true); + } + + protected void tearDown() throws Exception { + JSONDruidStatService.getInstance().setResetEnable(true); + } + + public void test_resetEnable_none() throws Exception { + Assert.assertTrue(JSONDruidStatService.getInstance().isResetEnable()); + + MockServletConfig servletConfig = new MockServletConfig(); + + StatViewServlet servlet = new StatViewServlet(); + servlet.init(servletConfig); + + Assert.assertTrue(JSONDruidStatService.getInstance().isResetEnable()); + } + + public void test_resetEnable_true() throws Exception { + Assert.assertTrue(JSONDruidStatService.getInstance().isResetEnable()); + + MockServletConfig servletConfig = new MockServletConfig(); + servletConfig.addInitParameter(StatViewServlet.PARAM_NAME_RESET_ENABLE, "true"); + + StatViewServlet servlet = new StatViewServlet(); + servlet.init(servletConfig); + + Assert.assertTrue(JSONDruidStatService.getInstance().isResetEnable()); + } + + public void test_resetEnable_empty() throws Exception { + Assert.assertTrue(JSONDruidStatService.getInstance().isResetEnable()); + + MockServletConfig servletConfig = new MockServletConfig(); + servletConfig.addInitParameter(StatViewServlet.PARAM_NAME_RESET_ENABLE, ""); + + StatViewServlet servlet = new StatViewServlet(); + servlet.init(servletConfig); + + Assert.assertTrue(JSONDruidStatService.getInstance().isResetEnable()); + } + + public void test_resetEnable_false() throws Exception { + Assert.assertTrue(JSONDruidStatService.getInstance().isResetEnable()); + + MockServletConfig servletConfig = new MockServletConfig(); + servletConfig.addInitParameter(StatViewServlet.PARAM_NAME_RESET_ENABLE, "false"); + + StatViewServlet servlet = new StatViewServlet(); + servlet.init(servletConfig); + + Assert.assertFalse(JSONDruidStatService.getInstance().isResetEnable()); + } + + public void test_resetEnable_error() throws Exception { + Assert.assertTrue(JSONDruidStatService.getInstance().isResetEnable()); + + MockServletConfig servletConfig = new MockServletConfig(); + servletConfig.addInitParameter(StatViewServlet.PARAM_NAME_RESET_ENABLE, "xxx"); + + StatViewServlet servlet = new StatViewServlet(); + servlet.init(servletConfig); + + Assert.assertFalse(JSONDruidStatService.getInstance().isResetEnable()); + } +} diff --git a/src/test/java/com/alibaba/druid/util/IpUtilsTest.java b/src/test/java/com/alibaba/druid/util/IpUtilsTest.java deleted file mode 100644 index aa9ea23c6a..0000000000 --- a/src/test/java/com/alibaba/druid/util/IpUtilsTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.alibaba.druid.util; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.junit.Test; -import org.junit.Assert; - - -public class IpUtilsTest { - - - @Test - public void testBuildIpCheckPattern() { - - Pattern pat = IpUtils.buildIpCheckPattern("192.168.0.*"); - String[] validIps = {"192.168.0.1", "192.168.0.2","192.168.0.15","192.168.0.250"}; - String[] inValidIps = {"192.168.15.1", "192.168.7.1","10.8.9.25","168.2.3.10"}; - checkIp(pat, validIps, inValidIps); - - pat = IpUtils.buildIpCheckPattern("192.168.0.1"); - validIps = new String[] {"192.168.0.1"}; - inValidIps = new String[] {"192.168.0.2", "192.168.1.0","10.15.255.3"}; - checkIp(pat, validIps, inValidIps); - - pat = IpUtils.buildIpCheckPattern("192.168.0.1,192.168.0.2,192.168.1.*"); - validIps = new String[] {"192.168.0.1","192.168.0.2","192.168.1.15"}; - inValidIps = new String[] {"192.168.0.3", "192.168.10.2","10.15.255.3","16.8.155.3"}; - checkIp(pat, validIps, inValidIps); - - - } - - private void checkIp(Pattern pat, String[] validIps, String[] inValidIps) { - Matcher matcher = null; - for (String validIp : validIps) { - matcher = pat.matcher(validIp); - Assert.assertTrue(matcher.matches()); - } - - for (String inValidIp : inValidIps) { - matcher = pat.matcher(inValidIp); - Assert.assertFalse(matcher.matches()); - } - } - -}