1
18 package net.bull.javamelody.internal.web.html;
19
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.LinkedHashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.regex.Pattern;
26
27
31 final class JavaHTMLizer {
32 private static final String BR = "<br />\n";
33
34 private static final List<Pattern> RESERVED_WORDS_PATTERNS = createReservedWordPatterns(
35 Arrays.asList("class", "finally", "return", "new", "public", "static", "final", "void",
36 "synchronized", "interface", "enum", "private", "protected", "import",
37 "package", "try", "catch", "for", "while", "do", "if", "else", "switch", "case",
38 "default", "goto", "byte", "short", "int", "long", "float", "double", "char",
39 "boolean", "extends", "implements", "super", "this", "true", "false", "null",
40 "abstract", "break", "continue", "assert", "instanceof", "native", "strictfp",
41 "throws", "throw", "transient", "volatile"));
42
43 private static final Map<Character, String> ESCAPE_MAPS = createEscapeMaps();
44
45 private static final Pattern MULTILINE_COMMENT_PATTERN = Pattern.compile("/\\*(.*?)\\*/",
46 Pattern.DOTALL);
47
48 private static final Pattern SINGLELINE_COMMENT_PATTERN = Pattern.compile(",
49 Pattern.DOTALL);
50
51 private static final Pattern STRING_PATTERN = Pattern.compile(""(.*?)"");
52
53 private JavaHTMLizer() {
54 super();
55 }
56
57 static String htmlize(final String javaSource) {
58 String result = "-" + javaSource;
59 result = htmlEscape(result);
60 result = formatReservedWords(result);
61 result = formatComments(result);
62 result = formatStrings(result);
63 return result.substring(1);
64 }
65
66 static String htmlizeFull(final String javaSource) {
67 final String result = htmlize(javaSource);
68 final String start = "<html><body><style>" + "code { font-size: 12px; } "
69 + "code .string { color: blue; } "
70 + "code .comment { font-style: italic; color: green; } "
71 + "code .keyword { font-weight: bold; color: purple; } "
72 + "code .comment .keyword { color: green; font-weight: normal; } "
73 + "code .comment .string { color: green; } " + "</style><code>";
74 final String end = "</code></body></html>";
75 return start + result + end;
76 }
77
78 static String addLineNumbers(final String javaSource) {
79 final StringBuilder sb = new StringBuilder(javaSource);
80 sb.insert(0, "<a name=1 href=#1>1</a> ");
81 int line = 2;
82 int index = sb.indexOf(BR);
83 while (index != -1) {
84 final int offset = index + BR.length();
85 final String strLine = Integer.toString(line);
86 sb.insert(offset, "</a> ");
87 sb.insert(offset, strLine);
88 sb.insert(offset, '>');
89 sb.insert(offset, strLine);
90 sb.insert(offset, " href=#");
91 sb.insert(offset, strLine);
92 sb.insert(offset, "<a name=");
93 index = sb.indexOf(BR, index + 1);
94 line++;
95 }
96 return sb.toString();
97 }
98
99 private static List<Pattern> createReservedWordPatterns(final List<String> reservedWords) {
100 final List<Pattern> result = new ArrayList<>(reservedWords.size());
101 for (final String reservedWord : reservedWords) {
102 result.add(Pattern.compile("(\\W)(" + reservedWord + ")(\\W)"));
103 }
104 return result;
105 }
106
107 private static Map<Character, String> createEscapeMaps() {
108 final Map<Character, String> escapeMaps = new LinkedHashMap<>();
109 escapeMaps.put(' ', " ");
110 escapeMaps.put('\t', " ");
111 escapeMaps.put('<', "<");
112 escapeMaps.put('>', ">");
113 escapeMaps.put('\"', """);
114 escapeMaps.put('&', "&");
115 escapeMaps.put('\'', "'");
116 escapeMaps.put('\n', BR);
117 return escapeMaps;
118 }
119
120 private static String escapeChar(final char c) {
121 return ESCAPE_MAPS.get(c);
122 }
123
124 private static String htmlEscape(final String text) {
125 final StringBuilder sb = new StringBuilder();
126 for (int i = 0; i < text.length(); i++) {
127 final char c = text.charAt(i);
128 final String escapedOrNull = escapeChar(c);
129 if (escapedOrNull == null) {
130 sb.append(c);
131 } else {
132 sb.append(escapedOrNull);
133 }
134 }
135 return sb.toString();
136 }
137
138 private static String formatReservedWords(final String text) {
139 String result = text;
140 for (final Pattern reservedWordPattern : RESERVED_WORDS_PATTERNS) {
141 result = reservedWordPattern.matcher(result)
142 .replaceAll("$1<span class=\"keyword\">$2</span>$3");
143 }
144 return result;
145 }
146
147 private static String formatComments(final String text) {
148 String result = text;
149 result = MULTILINE_COMMENT_PATTERN.matcher(result)
150 .replaceAll("<span class=\"comment\"></span>");
151 result = SINGLELINE_COMMENT_PATTERN.matcher(result)
152 .replaceAll("<span class=\"comment\">);
153 return result;
154 }
155
156 private static String formatStrings(final String text) {
157 return STRING_PATTERN.matcher(text)
158 .replaceAll("<span class=\"string\">"$1"</span>");
159 }
160 }
161