/*
* Copyright (c) 2012-2017 Mozilla Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
package nu.validator.servlet;
import java.io.IOException;
import java.text.DecimalFormat;
import javax.servlet.http.HttpServletResponse;
import nu.validator.htmlparser.sax.HtmlSerializer;
import nu.validator.xml.EmptyAttributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
public class Statistics {
public static final Statistics STATISTICS;
private static final char[] VALIDATOR_STATISTICS = "Validator statistics".toCharArray();
private static final char[] COUNTER_NAME = "Counter".toCharArray();
private static final char[] COUNTER_VALUE = "Value".toCharArray();
private static final char[] COUNTER_PROPORTION = "Proportion".toCharArray();
private static final char[] TOTAL_VALIDATIONS = "Total number of validations".toCharArray();
private static final char[] UPTIME_DAYS = "Uptime in days".toCharArray();
private static final char[] VALIDATIONS_PER_SECOND = "Validations per second".toCharArray();
private static final char[] SORT_LANGS_SCRIPT = (""
+ " var rows = document.querySelectorAll('tr');"
+ " var langRows = new Array();"
+ " for (var i=0; i < rows.length; i++) { var row = rows[i];"
+ " if (row.textContent.indexOf('Detected language') > -1) {"
+ " var sortnr = parseInt(row.cells[1].textContent"
+ " || row.cells[0].innerText);"
+ " if (sortnr == 0) {"
+ " row.remove();"
+ " } else if (!isNaN(sortnr)) {"
+ " langRows.push([sortnr, row]);"
+ " }"
+ " }"
+ " } langRows.sort(function(x,y) { return x[0] - y[0]; });"
+ " langRows.reverse();"
+ " for (var i=0; i<langRows.length; i++) {"
+ " document.querySelector('tbody').appendChild(langRows[i][1]);"
+ " }"
+ " var langValRows = new Array();"
+ " for (var i=0; i < rows.length; i++) { var row = rows[i];"
+ " if (row.textContent.indexOf('<html lang>: ') > -1) {"
+ " var sortnr = parseInt(row.cells[1].textContent"
+ " || row.cells[0].innerText);"
+ " if (sortnr == 0) {"
+ " row.remove();"
+ " } else if (!isNaN(sortnr)) {"
+ " langValRows.push([sortnr, row]);"
+ " }"
+ " }"
+ " } langValRows.sort(function(x,y) { return x[0] - y[0]; });"
+ " langValRows.reverse();"
+ " for (var i=0; i<langValRows.length; i++) {"
+ " document.querySelector('tbody').appendChild(langValRows[i][1]);"
+ " }").toCharArray();
private static final char[] STYLESHEET = (""
+ " body { font-family: sans-serif; }"
+ " td { padding: 4px 8px 4px 8px; }"
+ " tr:nth-child(even) { background-color: #cde; }").toCharArray();
public enum Field {
// @formatter:off
INPUT_GET("Input: GET-based"), //
INPUT_POST("Input: POST-based"), //
INPUT_ENTITY_BODY("\u2514 Entity-body input"), //
INPUT_TEXT_FIELD("\u2514 Text-field input"), //
INPUT_FILE_UPLOAD("\u2514 File-upload input"), //
INPUT_HTML("Input: text/html"), //
INPUT_UNSUPPORTED("Input: unsupported content type (error)"), //
INPUT_XML("Input: application/xhtml+xml or other XML content type"), //
OUTPUT_XML("Output: XML"), //
OUTPUT_HTML("Output: HTML"), //
OUTPUT_JSON("Output: JSON"), //
OUTPUT_GNU("Output: GNU"), //
OUTPUT_TEXT("Output: Text"), //
OUTPUT_XHTML("Output: XHTML"), //
SHOW_SOURCE("Show: source"), //
SHOW_OUTLINE("Show: outline"), //
IMAGE_REPORT("Show: image report"), //
HTML5_SCHEMA("Schema: HTML5 schema"), //
HTML5_RDFA_LITE_SCHEMA("Schema: HTML5+RDFa Lite schema"), //
XHTML1_DOCTYPE("Doctype: XHTML1"), //
HTML4_DOCTYPE("Doctype: HTML4"), //
ABOUT_LEGACY_COMPAT("Doctype: about:legacy-compat"), //
AUTO_SCHEMA("Schema: automatically chosen"), //
PRESET_SCHEMA("Schema: preset"), //
HTML4_STRICT_SCHEMA("Schema: legacy Strict"), //
HTML4_TRANSITIONAL_SCHEMA("Schema: legacy Transitional"), //
HTML4_FRAMESET_SCHEMA("Schema: legacy Frameset"), //
XHTML1_COMPOUND_SCHEMA("Schema: legacy XHTML+SVG+MathML"), //
SVG_SCHEMA("Schema: SVG"), //
BUILT_IN_NON_PRESET("Schema: custom combined from built-ins"), //
EXTERNAL_SCHEMA_NON_SCHEMATRON("Schema: non-schematron custom"), //
EXTERNAL_SCHEMA_SCHEMATRON("Schema: schematron custom"), //
LAX_TYPE("Content type: being lax"), //
CUSTOM_ENC("Encoding: manually set"), //
PARSER_XML_EXTERNAL("Parser: set to XML with external entities"), //
PARSER_HTML4("Parser: set to explicit HTML4 mode"), //
XMLNS_FILTER("Parser: XMLNS filter set"), //
LOGIC_ERROR("Logic errors in schema stats"), //
STYLE_IN_BODY_FOUND("<style> in <body> found"), //
REL_ALTERNATE_FOUND("rel=alternate found"), //
REL_AUTHOR_FOUND("rel=author found"), //
REL_BOOKMARK_FOUND("rel=bookmark found"), //
REL_CANONICAL_FOUND("rel=canonical found"), //
REL_DNS_PREFETCH_FOUND("rel=dns-prefetch found"), //
REL_EXTERNAL_FOUND("rel=external found"), //
REL_HELP_FOUND("rel=help found"), //
REL_ICON_FOUND("rel=icon found"), //
REL_LICENSE_FOUND("rel=license found"), //
REL_NEXT_FOUND("rel=next found"), //
REL_NOFOLLOW_FOUND("rel=nofollow found"), //
REL_NOOPENER_FOUND("rel=noopener found"), //
REL_NOREFERRER_FOUND("rel=noreferrer found"), //
REL_PINGBACK_FOUND("rel=pingback found"), //
REL_PRECONNECT_FOUND("rel=preconnect found"), //
REL_PREFETCH_FOUND("rel=prefetch found"), //
REL_PRELOAD_FOUND("rel=preload found"), //
REL_PRERENDER_FOUND("rel=prerender found"), //
REL_PREV_FOUND("rel=prev found"), //
REL_SEARCH_FOUND("rel=search found"), //
REL_SERVICEWORKER_FOUND("rel=serviceworker found"), //
REL_STYLESHEET_FOUND("rel=stylesheet found"), //
REL_TAG_FOUND("rel=tag found"), //
APPLE_TOUCH_ICON_WITH_SIZES_FOUND("<link rel=\"apple-touch-icon\" sizes=\"\u2026\"> found"), //
LANG_FOUND("<html lang> found"), //
LANG_WRONG("<html lang> does not match detected language"), //
LANG_EMPTY("<html lang>: empty (lang=\"\")"), //
LANG_OTHER("<html lang>: other (unrecognized/invalid)"), //
LANG_AF("<html lang>: af"), //
LANG_AM("<html lang>: am"), //
LANG_AR("<html lang>: ar"), //
LANG_AR_AA("<html lang>: ar-aa"), //
LANG_AR_AE("<html lang>: ar-ae"), //
LANG_AR_AR("<html lang>: ar-ar"), //
LANG_AR_DZ("<html lang>: ar-dz"), //
LANG_AR_EG("<html lang>: ar-eg"), //
LANG_AR_JO("<html lang>: ar-jo"), //
LANG_AR_KW("<html lang>: ar-kw"), //
LANG_AR_OM("<html lang>: ar-om"), //
LANG_AR_QA("<html lang>: ar-qa"), //
LANG_AR_SA("<html lang>: ar-sa"), //
LANG_AR_SY("<html lang>: ar-sy"), //
LANG_AT("<html lang>: at"), //
LANG_AZ("<html lang>: az"), //
LANG_AZ_AZ("<html lang>: az-az"), //
LANG_BA("<html lang>: ba"), //
LANG_BE("<html lang>: be"), //
LANG_BG("<html lang>: bg"), //
LANG_BG_BG("<html lang>: bg-bg"), //
LANG_BN("<html lang>: bn"), //
LANG_BN_BD("<html lang>: bn-bd"), //
LANG_BR("<html lang>: br"), //
LANG_BS("<html lang>: bs"), //
LANG_BS_BA("<html lang>: bs-ba"), //
LANG_BS_LATN("<html lang>: bs-latn"), //
LANG_CA("<html lang>: ca"), //
LANG_CA_ES("<html lang>: ca-es"), //
LANG_CE("<html lang>: ce"), //
LANG_CH("<html lang>: ch"), //
LANG_CHR("<html lang>: chr"), //
LANG_CKB("<html lang>: ckb"), //
LANG_CN("<html lang>: cn"), //
LANG_CR("<html lang>: cr"), //
LANG_CS("<html lang>: cs"), //
LANG_CS_CZ("<html lang>: cs-cz"), //
LANG_CY("<html lang>: cy"), //
LANG_CZ("<html lang>: cz"), //
LANG_DA("<html lang>: da"), //
LANG_DA_DK("<html lang>: da-dk"), //
LANG_DE("<html lang>: de"), //
LANG_DE_AT("<html lang>: de-at"), //
LANG_DE_CH("<html lang>: de-ch"), //
LANG_DE_DE("<html lang>: de-de"), //
LANG_DE__DE("<html lang>: de_de"), //
LANG_DK("<html lang>: dk"), //
LANG_EL("<html lang>: el"), //
LANG_EL_GR("<html lang>: el-gr"), //
LANG_EN("<html lang>: en"), //
LANG_ENG("<html lang>: eng"), //
LANG_EN_AE("<html lang>: en-ae"), //
LANG_EN_AU("<html lang>: en-au"), //
LANG_EN__AU("<html lang>: en_au"), //
LANG_EN_CA("<html lang>: en-ca"), //
LANG_EN__CA("<html lang>: en_ca"), //
LANG_EN_DE("<html lang>: en-de"), //
LANG_EN_EG("<html lang>: en-eg"), //
LANG_EN_EN("<html lang>: en-en"), //
LANG_EN__EN("<html lang>: en_en"), //
LANG_EN_EU("<html lang>: en-eu"), //
LANG_EN_GB("<html lang>: en-gb"), //
LANG_EN__GB("<html lang>: en_gb"), //
LANG_EN_HK("<html lang>: en-hk"), //
LANG_EN_ID("<html lang>: en-id"), //
LANG_EN_IE("<html lang>: en-ie"), //
LANG_EN_IN("<html lang>: en-in"), //
LANG_EN_MY("<html lang>: en-my"), //
LANG_EN_NG("<html lang>: en-ng"), //
LANG_EN_NZ("<html lang>: en-nz"), //
LANG_EN_PH("<html lang>: en-ph"), //
LANG_EN_PK("<html lang>: en-pk"), //
LANG_EN_SG("<html lang>: en-sg"), //
LANG_EN_UK("<html lang>: en-uk"), //
LANG_EN_US("<html lang>: en-us"), //
LANG_EN__US("<html lang>: en_us"), //
LANG_EN_VN("<html lang>: en-vn"), //
LANG_EN_ZA("<html lang>: en-za"), //
LANG_ES("<html lang>: es"), //
LANG_ES_AR("<html lang>: es-ar"), //
LANG_ES__AR("<html lang>: es_ar"), //
LANG_ES_CL("<html lang>: es-cl"), //
LANG_ES_CO("<html lang>: es-co"), //
LANG_ES_DO("<html lang>: es-do"), //
LANG_ES_EC("<html lang>: es-ec"), //
LANG_ES_ES("<html lang>: es-es"), //
LANG_ES__ES("<html lang>: es_es"), //
LANG_ES_LA("<html lang>: es-la"), //
LANG_ES_MX("<html lang>: es-mx"), //
LANG_ES_PE("<html lang>: es-pe"), //
LANG_ES_PR("<html lang>: es-pr"), //
LANG_ES_US("<html lang>: es-us"), //
LANG_ES_VE("<html lang>: es-ve"), //
LANG_ET("<html lang>: et"), //
LANG_ET_EE("<html lang>: et-ee"), //
LANG_EU("<html lang>: eu"), //
LANG_FA("<html lang>: fa"), //
LANG_FA_IR("<html lang>: fa-ir"), //
LANG_FA__IR("<html lang>: fa_ir"), //
LANG_FI("<html lang>: fi"), //
LANG_FI_FI("<html lang>: fi-fi"), //
LANG_FO("<html lang>: fo"), //
LANG_FR("<html lang>: fr"), //
LANG_FR_BE("<html lang>: fr-be"), //
LANG_FR_CA("<html lang>: fr-ca"), //
LANG_FR_CH("<html lang>: fr-ch"), //
LANG_FR_FR("<html lang>: fr-fr"), //
LANG_FR__FR("<html lang>: fr_fr"), //
LANG_FR_MA("<html lang>: fr-ma"), //
LANG_FR_US("<html lang>: fr-us"), //
LANG_GA("<html lang>: ga"), //
LANG_GB("<html lang>: gb"), //
LANG_GE("<html lang>: ge"), //
LANG_GL("<html lang>: gl"), //
LANG_GL_ES("<html lang>: gl-es"), //
LANG_GR("<html lang>: gr"), //
LANG_GU("<html lang>: gu"), //
LANG_HE("<html lang>: he"), //
LANG_HE_IL("<html lang>: he-il"), //
LANG_HI("<html lang>: hi"), //
LANG_HR_HR("<html lang>: hr-hr"), //
LANG_HU("<html lang>: hu"), //
LANG_HU_HU("<html lang>: hu-hu"), //
LANG_HY("<html lang>: hy"), //
LANG_HY_AM("<html lang>: hy-am"), //
LANG_ID("<html lang>: id"), //
LANG_ID_ID("<html lang>: id-id"), //
LANG_IG("<html lang>: ig"), //
LANG_IN("<html lang>: in"), //
LANG_IN_ID("<html lang>: in-id"), //
LANG_IR("<html lang>: ir"), //
LANG_IS("<html lang>: is"), //
LANG_IT("<html lang>: it"), //
LANG_IT_IT("<html lang>: it-it"), //
LANG_IT__IT("<html lang>: it_it"), //
LANG_IU("<html lang>: iu"), //
LANG_IW("<html lang>: iw"), //
LANG_JA("<html lang>: ja"), //
LANG_JA_JP("<html lang>: ja-jp"), //
LANG_JA__JP("<html lang>: ja_jp"), //
LANG_JP("<html lang>: jp"), //
LANG_JV("<html lang>: jv"), //
LANG_KA("<html lang>: ka"), //
LANG_KA_GE("<html lang>: ka-ge"), //
LANG_KK("<html lang>: kk"), //
LANG_KK_KK("<html lang>: kk-kk"), //
LANG_KK_KZ("<html lang>: kk-kz"), //
LANG_KM("<html lang>: km"), //
LANG_KN("<html lang>: kn"), //
LANG_KO("<html lang>: ko"), //
LANG_KO_KR("<html lang>: ko-kr"), //
LANG_KR("<html lang>: kr"), //
LANG_KU("<html lang>: ku"), //
LANG_KY("<html lang>: ky"), //
LANG_KZ("<html lang>: kz"), //
LANG_KZ_KZ("<html lang>: kz-kz"), //
LANG_LANG("<html lang>: lang"), //
LANG_LO("<html lang>: lo"), //
LANG_LT("<html lang>: lt"), //
LANG_LT_LT("<html lang>: lt-lt"), //
LANG_LV("<html lang>: lv"), //
LANG_LV_LV("<html lang>: lv-lv"), //
LANG_MG("<html lang>: mg"), //
LANG_MHR("<html lang>: mhr"), //
LANG_MI("<html lang>: mi"), //
LANG_MK("<html lang>: mk"), //
LANG_MK_MK("<html lang>: mk-mk"), //
LANG_ML("<html lang>: ml"), //
LANG_MN("<html lang>: mn"), //
LANG_MN_MN("<html lang>: mn-mn"), //
LANG_MR("<html lang>: mr"), //
LANG_MRJ("<html lang>: mrj"), //
LANG_MR_IN("<html lang>: mr-in"), //
LANG_MS("<html lang>: ms"), //
LANG_MS_MY("<html lang>: ms-my"), //
LANG_MT("<html lang>: mt"), //
LANG_MUL("<html lang>: mul"), //
LANG_MX("<html lang>: mx"), //
LANG_MY("<html lang>: my"), //
LANG_NAH("<html lang>: nah"), //
LANG_NB_NO("<html lang>: nb-no"), //
LANG_NE("<html lang>: ne"), //
LANG_NL("<html lang>: nl"), //
LANG_NL_BE("<html lang>: nl-be"), //
LANG_NL_NL("<html lang>: nl-nl"), //
LANG_NL__NL("<html lang>: nl_nl"), //
LANG_NN("<html lang>: nn"), //
LANG_NO("<html lang>: no"), //
LANG_NO_NB("<html lang>: no-nb"), //
LANG_NO_NO("<html lang>: no-no"), //
LANG_NY("<html lang>: ny"), //
LANG_OC("<html lang>: oc"), //
LANG_OR("<html lang>: or"), //
LANG_OS("<html lang>: os"), //
LANG_PA("<html lang>: pa"), //
LANG_PL("<html lang>: pl"), //
LANG_PL_PL("<html lang>: pl-pl"), //
LANG_PL__PL("<html lang>: pl_pl"), //
LANG_PNB("<html lang>: pnb"), //
LANG_PS("<html lang>: ps"), //
LANG_PT("<html lang>: pt"), //
LANG_PT_BR("<html lang>: pt-br"), //
LANG_PT__BR("<html lang>: pt_br"), //
LANG_PT_PT("<html lang>: pt-pt"), //
LANG_RO("<html lang>: ro"), //
LANG_RO_RO("<html lang>: ro-ro"), //
LANG_RO__RO("<html lang>: ro_ro"), //
LANG_RS("<html lang>: rs"), //
LANG_RU("<html lang>: ru"), //
LANG_RU_RU("<html lang>: ru-ru"), //
LANG_RU__RU("<html lang>: ru_ru"), //
LANG_RU_UA("<html lang>: ru-ua"), //
LANG_RW("<html lang>: rw"), //
LANG_SAH("<html lang>: sah"), //
LANG_SD("<html lang>: sd"), //
LANG_SE("<html lang>: se"), //
LANG_SH("<html lang>: sh"), //
LANG_SI("<html lang>: si"), //
LANG_SK("<html lang>: sk"), //
LANG_SK_SK("<html lang>: sk-sk"), //
LANG_SL("<html lang>: sl"), //
LANG_SL_SI("<html lang>: sl-si"), //
LANG_SN("<html lang>: sn"), //
LANG_SP("<html lang>: sp"), //
LANG_SQ("<html lang>: sq"), //
LANG_SQ_AL("<html lang>: sq-al"), //
LANG_SR("<html lang>: sr"), //
LANG_SR_LATN("<html lang>: sr-latn"), //
LANG_SR_RS("<html lang>: sr-rs"), //
LANG_SR_SR("<html lang>: sr-sr"), //
LANG_SR_YU("<html lang>: sr-yu"), //
LANG_ST("<html lang>: st"), //
LANG_SU("<html lang>: su"), //
LANG_SV("<html lang>: sv"), //
LANG_SV_SE("<html lang>: sv-se"), //
LANG_SW("<html lang>: sw"), //
LANG_TA("<html lang>: ta"), //
LANG_TE("<html lang>: te"), //
LANG_TG("<html lang>: tg"), //
LANG_TH("<html lang>: th"), //
LANG_TH_TH("<html lang>: th-th"), //
LANG_TL("<html lang>: tl"), //
LANG_TR("<html lang>: tr"), //
LANG_TR_TR("<html lang>: tr-tr"), //
LANG_TR__TR("<html lang>: tr_tr"), //
LANG_TT("<html lang>: tt"), //
LANG_TW("<html lang>: tw"), //
LANG_UA("<html lang>: ua"), //
LANG_UG("<html lang>: ug"), //
LANG_UK("<html lang>: uk"), //
LANG_UK_UA("<html lang>: uk-ua"), //
LANG_UR("<html lang>: ur"), //
LANG_UR_PK("<html lang>: ur-pk"), //
LANG_US("<html lang>: us"), //
LANG_US_EN("<html lang>: us-en"), //
LANG_UZ("<html lang>: uz"), //
LANG_VI("<html lang>: vi"), //
LANG_VI_VN("<html lang>: vi-vn"), //
LANG_VI__VN("<html lang>: vi_vn"), //
LANG_VN("<html lang>: vn"), //
LANG_XH("<html lang>: xh"), //
LANG_ZH("<html lang>: zh"), //
LANG_ZH_CH("<html lang>: zh-ch"), //
LANG_ZH_CMN("<html lang>: zh-cmn"), //
LANG_ZH_CMN_HANS("<html lang>: zh-cmn-hans"), //
LANG_ZH_CMN_HANT("<html lang>: zh-cmn-hant"), //
LANG_ZH_CN("<html lang>: zh-cn"), //
LANG_ZH__CN("<html lang>: zh_cn"), //
LANG_ZH_HANS("<html lang>: zh-hans"), //
LANG_ZH_HANS_CN("<html lang>: zh-hans-cn"), //
LANG_ZH_HANT("<html lang>: zh-hant"), //
LANG_ZH_HANT_HK("<html lang>: zh-hant-hk"), //
LANG_ZH_HANT_TW("<html lang>: zh-hant-tw"), //
LANG_ZH_HK("<html lang>: zh-hk"), //
LANG_ZH__HK("<html lang>: zh_hk"), //
LANG_ZH_TW("<html lang>: zh-tw"), //
LANG_ZH__TW("<html lang>: zh_tw"), //
LANG_ZU("<html lang>: zu"), //
LANG_ZXX("<html lang>: zxx"), //
DETECTEDLANG_AF("Detected language: Afrikaans"), //
DETECTEDLANG_AZB("Detected language: South Azerbaijani"), //
DETECTEDLANG_AM("Detected language: Amharic"), //
DETECTEDLANG_AR("Detected language: Arabic"), //
DETECTEDLANG_AZ("Detected language: Azerbaijani"), //
DETECTEDLANG_BA("Detected language: Bashkir"), //
DETECTEDLANG_BE("Detected language: Belarusian"), //
DETECTEDLANG_BN("Detected language: Bengali"), //
DETECTEDLANG_BO("Detected language: Tibetan"), //
DETECTEDLANG_BS("Detected language: Bosnian"), //
DETECTEDLANG_CA("Detected language: Catalan"), //
DETECTEDLANG_CE("Detected language: Chechen"), //
DETECTEDLANG_CHR("Detected language: Cherokee"), //
DETECTEDLANG_CKB("Detected language: Sorani Kurdish"), //
DETECTEDLANG_CR("Detected language: Cree"), //
DETECTEDLANG_CS("Detected language: Czech"), //
DETECTEDLANG_CY("Detected language: Welsh"), //
DETECTEDLANG_DA("Detected language: Danish"), //
DETECTEDLANG_DE("Detected language: German"), //
DETECTEDLANG_DV("Detected language: Divehi"), //
DETECTEDLANG_EL("Detected language: Greek"), //
DETECTEDLANG_EN("Detected language: English"), //
DETECTEDLANG_ES("Detected language: Spanish"), //
DETECTEDLANG_ET("Detected language: Estonian"), //
DETECTEDLANG_EU("Detected language: Basque"), //
DETECTEDLANG_FA("Detected language: Persian"), //
DETECTEDLANG_FI("Detected language: Finnish"), //
DETECTEDLANG_FO("Detected language: Faroese"), //
DETECTEDLANG_FR("Detected language: French"), //
DETECTEDLANG_GA("Detected language: Irish"), //
DETECTEDLANG_GU("Detected language: Gujarati"), //
DETECTEDLANG_HA("Detected language: Hausa"), //
DETECTEDLANG_HE("Detected language: Hebrew"), //
DETECTEDLANG_HI("Detected language: Hindi"), //
DETECTEDLANG_HR("Detected language: Croatian"), //
DETECTEDLANG_HU("Detected language: Hungarian"), //
DETECTEDLANG_HY("Detected language: Armenian"), //
DETECTEDLANG_ID("Detected language: Indonesian"), //
DETECTEDLANG_IG("Detected language: Igbo"), //
DETECTEDLANG_IS("Detected language: Icelandic"), //
DETECTEDLANG_IT("Detected language: Italian"), //
DETECTEDLANG_IU("Detected language: Inuktitut"), //
DETECTEDLANG_JA("Detected language: Japanese"), //
DETECTEDLANG_JV("Detected language: Javanese"), //
DETECTEDLANG_KA("Detected language: Georgian"), //
DETECTEDLANG_KM("Detected language: Khmer"), //
DETECTEDLANG_KK("Detected language: Kazakh"), //
DETECTEDLANG_KN("Detected language: Kannada"), //
DETECTEDLANG_KO("Detected language: Korean"), //
DETECTEDLANG_KU("Detected language: Kurdish"), //
DETECTEDLANG_KY("Detected language: Kyrgyz"), //
DETECTEDLANG_LO("Detected language: Lao"), //
DETECTEDLANG_LT("Detected language: Lithuanian"), //
DETECTEDLANG_LV("Detected language: Latvian"), //
DETECTEDLANG_MG("Detected language: Malagasy"), //
DETECTEDLANG_MHR("Detected language: Meadow Mari"), //
DETECTEDLANG_MI("Detected language: Maori"), //
DETECTEDLANG_MK("Detected language: Macedonian"), //
DETECTEDLANG_ML("Detected language: Malayalam"), //
DETECTEDLANG_MN("Detected language: Mongolian"), //
DETECTEDLANG_MR("Detected language: Marathi"), //
DETECTEDLANG_MRJ("Detected language: Hill Mari"), //
DETECTEDLANG_MS("Detected language: Malay"), //
DETECTEDLANG_MT("Detected language: Maltese"), //
DETECTEDLANG_MY("Detected language: Burmese"), //
DETECTEDLANG_NAH("Detected language: Nahuatl"), //
DETECTEDLANG_NE("Detected language: Nepali"), //
DETECTEDLANG_NL("Detected language: Dutch"), //
DETECTEDLANG_NO("Detected language: Norwegian"), //
DETECTEDLANG_NY("Detected language: Nyanja"), //
DETECTEDLANG_OC("Detected language: Occitan"), //
DETECTEDLANG_OM("Detected language: Oromo"), //
DETECTEDLANG_OR("Detected language: Oriya"), //
DETECTEDLANG_OS("Detected language: Ossetian"), //
DETECTEDLANG_PA("Detected language: Punjabi"), //
DETECTEDLANG_PL("Detected language: Polish"), //
DETECTEDLANG_PNB("Detected language: Western Panjabi"), //
DETECTEDLANG_PS("Detected language: Pashto"), //
DETECTEDLANG_PT("Detected language: Portuguese"), //
DETECTEDLANG_RO("Detected language: Romanian"), //
DETECTEDLANG_RU("Detected language: Russian"), //
DETECTEDLANG_RW("Detected language: Kinyarwanda"), //
DETECTEDLANG_SAH("Detected language: Sakha"), //
DETECTEDLANG_SD("Detected language: Sindhi"), //
DETECTEDLANG_SH("Detected language: Croatian, Serbian, or Bosnian"), //
DETECTEDLANG_SI("Detected language: Sinhala"), //
DETECTEDLANG_SK("Detected language: Slovak"), //
DETECTEDLANG_SL("Detected language: Slovenian"), //
DETECTEDLANG_SN("Detected language: Shona"), //
DETECTEDLANG_SO("Detected language: Somali"), //
DETECTEDLANG_SQ("Detected language: Albanian"), //
DETECTEDLANG_SR_CYRL("Detected language: Serbian (Cyrillic)"), //
DETECTEDLANG_SR_LATN("Detected language: Serbian (Latin)"), //
DETECTEDLANG_ST("Detected language: Southern Sotho"), //
DETECTEDLANG_SU("Detected language: Sundanese"), //
DETECTEDLANG_SV("Detected language: Swedish"), //
DETECTEDLANG_SW("Detected language: Swahili"), //
DETECTEDLANG_TA("Detected language: Tamil"), //
DETECTEDLANG_TE("Detected language: Telugu"), //
DETECTEDLANG_TG("Detected language: Tajik"), //
DETECTEDLANG_TH("Detected language: Thai"), //
DETECTEDLANG_TI("Detected language: Tigrinya"), //
DETECTEDLANG_TL("Detected language: Tagalog"), //
DETECTEDLANG_TR("Detected language: Turkish"), //
DETECTEDLANG_TT("Detected language: Tatar"), //
DETECTEDLANG_UG("Detected language: Uyghur"), //
DETECTEDLANG_UK("Detected language: Ukrainian"), //
DETECTEDLANG_UR("Detected language: Urdu"), //
DETECTEDLANG_UZ_CYRL("Detected language: Uzbek (Cyrillic)"), //
DETECTEDLANG_UZ_LATN("Detected language: Uzbek (Latin)"), //
DETECTEDLANG_VI("Detected language: Vietnamese"), //
DETECTEDLANG_XH("Detected language: Xhosa"), //
DETECTEDLANG_ZH_HANS("Detected language: Simplified Chinese"), //
DETECTEDLANG_ZH_HANT("Detected language: Traditional Chinese"), //
DETECTEDLANG_ZU("Detected language: Zulu"), //
DETECTEDLANG_ZXX("Detected language: Lorem ipsum text"); //
// @formatter:on
Field(String description) {
this.description = description;
}
private final String description;
/**
* @see java.lang.Enum#toString()
*/
@Override
public String toString() {
return description;
}
}
public Field getFieldFromName(String name) {
for (Field field : Field.class.getEnumConstants()) {
if (field.name().equals(name)) {
return field;
}
}
throw new IllegalArgumentException(
"No statistics field with name " + name);
}
static {
if ("1".equals(System.getProperty("nu.validator.servlet.statistics"))) {
STATISTICS = new Statistics();
} else {
STATISTICS = null;
}
}
private final long startTime = System.currentTimeMillis();
private long total = 0;
private final long[] counters;
private Statistics() {
counters = new long[Field.values().length];
}
public void incrementTotal() {
total++;
}
public void incrementField(Field field) {
counters[field.ordinal()]++;
}
public void writeToResponse(HttpServletResponse response)
throws IOException {
try {
long totalCopy;
long[] countersCopy = new long[counters.length];
synchronized (this) {
totalCopy = total;
System.arraycopy(counters, 0, countersCopy, 0, counters.length);
}
double totalDouble = totalCopy;
double uptimeMillis = System.currentTimeMillis() - startTime;
response.setContentType("text/html; charset=utf-8");
ContentHandler ch = new HtmlSerializer(response.getOutputStream());
try {
ch.startDocument();
startElement(ch, "html");
startElement(ch, "head");
startElement(ch, "title");
characters(ch, VALIDATOR_STATISTICS);
endElement(ch, "title");
startElement(ch, "style");
characters(ch, STYLESHEET);
endElement(ch, "style");
endElement(ch, "head");
startElement(ch, "body");
startElement(ch, "h1");
characters(ch, VALIDATOR_STATISTICS);
endElement(ch, "h1");
startElement(ch, "dl");
startElement(ch, "dt");
characters(ch, TOTAL_VALIDATIONS);
endElement(ch, "dt");
startElement(ch, "dd");
characters(ch, totalCopy);
endElement(ch, "dd");
startElement(ch, "dt");
characters(ch, UPTIME_DAYS);
endElement(ch, "dt");
startElement(ch, "dd");
characters(ch, uptimeMillis / (1000 * 60 * 60 * 24));
endElement(ch, "dd");
startElement(ch, "dt");
characters(ch, VALIDATIONS_PER_SECOND);
endElement(ch, "dt");
startElement(ch, "dd");
characters(ch, totalDouble / (uptimeMillis / 1000.0));
endElement(ch, "dd");
endElement(ch, "dl");
startElement(ch, "table");
startElement(ch, "thead");
startElement(ch, "tr");
startElement(ch, "th");
characters(ch, COUNTER_NAME);
endElement(ch, "th");
startElement(ch, "th");
characters(ch, COUNTER_VALUE);
endElement(ch, "th");
startElement(ch, "th");
characters(ch, COUNTER_PROPORTION);
endElement(ch, "th");
endElement(ch, "tr");
endElement(ch, "thead");
startElement(ch, "tbody");
for (int i = 0; i < countersCopy.length; i++) {
long count = countersCopy[i];
startElement(ch, "tr");
startElement(ch, "td");
characters(ch, Field.values()[i].toString());
endElement(ch, "td");
startElement(ch, "td");
characters(ch, count);
endElement(ch, "td");
startElement(ch, "td");
characters(ch, count / totalDouble);
endElement(ch, "td");
endElement(ch, "tr");
}
endElement(ch, "tbody");
endElement(ch, "table");
startElement(ch, "script");
characters(ch, SORT_LANGS_SCRIPT);
endElement(ch, "script");
endElement(ch, "body");
endElement(ch, "html");
} finally {
ch.endDocument();
}
} catch (SAXException e) {
throw new IOException(e);
}
}
private void characters(ContentHandler ch, double d) throws SAXException {
// Let's just create a new DecimalFormat each time to avoid the
// complexity of recycling an instance correctly without threading
// hazards.
DecimalFormat df = new DecimalFormat("#,###,##0.000000");
characters(ch, df.format(d));
}
private void characters(ContentHandler ch, long l) throws SAXException {
characters(ch, Long.toString(l));
}
private void characters(ContentHandler ch, String str) throws SAXException {
characters(ch, str.toCharArray());
}
private void characters(ContentHandler ch, char[] cs) throws SAXException {
ch.characters(cs, 0, cs.length);
}
private void endElement(ContentHandler ch, String name)
throws SAXException {
ch.endElement("http://www.w3.org/1999/xhtml", name, name);
}
private void startElement(ContentHandler ch, String name)
throws SAXException {
ch.startElement("http://www.w3.org/1999/xhtml", name, name,
EmptyAttributes.EMPTY_ATTRIBUTES);
}
}