/* * Copyright 2008-2017 by Emeric Vernat * * This file is part of Java Melody. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.bull.javamelody; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; /** * Transformation de code source Java en HTML. * @author Emeric Vernat */ final class JavaHTMLizer { private static final String BR = "<br />\n"; private static final List<Pattern> RESERVED_WORDS_PATTERNS = createReservedWordPatterns( Arrays.asList("class", "finally", "return", "new", "public", "static", "final", "void", "synchronized", "interface", "enum", "private", "protected", "import", "package", "try", "catch", "for", "while", "do", "if", "else", "switch", "case", "default", "goto", "byte", "short", "int", "long", "float", "double", "char", "boolean", "extends", "implements", "super", "this", "true", "false", "null", "abstract", "break", "continue", "assert", "instanceof", "native", "strictfp", "throws", "throw", "transient", "volatile")); private static final Map<Character, String> ESCAPE_MAPS = createEscapeMaps(); private static final Pattern MULTILINE_COMMENT_PATTERN = Pattern.compile("\\/\\*(.*?)\\*\\/", Pattern.DOTALL); private static final Pattern SINGLELINE_COMMENT_PATTERN = Pattern.compile("\\/\\/(.*?)<br \\/>", Pattern.DOTALL); private static final Pattern STRING_PATTERN = Pattern.compile(""(.*?)""); private JavaHTMLizer() { super(); } static String htmlize(final String javaSource) { String result = "-" + javaSource; result = htmlEscape(result); result = formatReservedWords(result); result = formatComments(result); result = formatStrings(result); return result.substring(1); } static String htmlizeFull(final String javaSource) { final String result = htmlize(javaSource); final String start = "<html><body><style>" + "code { font-size: 12px; } " + "code .string { color: blue; } " + "code .comment { font-style: italic; color: green; } " + "code .keyword { font-weight: bold; color: purple; } " + "code .comment .keyword { color: green; font-weight: normal; } " + "code .comment .string { color: green; } " + "</style><code>"; final String end = "</code></body></html>"; return start + result + end; } static String addLineNumbers(final String javaSource) { final StringBuilder sb = new StringBuilder(javaSource); sb.insert(0, "<a name=1 href=#1>1</a> "); int line = 2; int index = sb.indexOf(BR); while (index != -1) { final int offset = index + BR.length(); final String strLine = Integer.toString(line); sb.insert(offset, "</a> "); sb.insert(offset, strLine); sb.insert(offset, '>'); sb.insert(offset, strLine); sb.insert(offset, " href=#"); sb.insert(offset, strLine); sb.insert(offset, "<a name="); index = sb.indexOf(BR, index + 1); line++; } return sb.toString(); } private static List<Pattern> createReservedWordPatterns(final List<String> reservedWords) { final List<Pattern> result = new ArrayList<Pattern>(reservedWords.size()); for (final String reservedWord : reservedWords) { result.add(Pattern.compile("(\\W)(" + reservedWord + ")(\\W)")); } return result; } private static Map<Character, String> createEscapeMaps() { final Map<Character, String> escapeMaps = new LinkedHashMap<Character, String>(); escapeMaps.put(' ', " "); escapeMaps.put('\t', "    "); escapeMaps.put('<', "<"); escapeMaps.put('>', ">"); escapeMaps.put('\"', """); escapeMaps.put('&', "&"); escapeMaps.put('\'', "'"); escapeMaps.put('\n', BR); return escapeMaps; } private static String escapeChar(final char c) { final String escaped = ESCAPE_MAPS.get(Character.valueOf(c)); if (escaped != null) { return escaped; } return null; } private static String htmlEscape(final String text) { final StringBuilder sb = new StringBuilder(); for (int i = 0; i < text.length(); i++) { final char c = text.charAt(i); final String escapedOrNull = escapeChar(c); if (escapedOrNull == null) { sb.append(c); } else { sb.append(escapedOrNull); } } return sb.toString(); } private static String formatReservedWords(final String text) { String result = text; for (final Pattern reservedWordPattern : RESERVED_WORDS_PATTERNS) { result = reservedWordPattern.matcher(result) .replaceAll("$1<span class=\"keyword\">$2</span>$3"); } return result; } private static String formatComments(final String text) { String result = text; result = MULTILINE_COMMENT_PATTERN.matcher(result) .replaceAll("<span class=\"comment\">/*$1*/</span>"); result = SINGLELINE_COMMENT_PATTERN.matcher(result) .replaceAll("<span class=\"comment\">//$1</span><br />"); return result; } private static String formatStrings(final String text) { return STRING_PATTERN.matcher(text) .replaceAll("<span class=\"string\">"$1"</span>"); } }