1
2
3
4
5
6
7
8
9
10
11 package psiprobe;
12
13 import com.google.common.base.Strings;
14
15 import java.io.BufferedInputStream;
16 import java.io.BufferedReader;
17 import java.io.ByteArrayInputStream;
18 import java.io.ByteArrayOutputStream;
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.InputStreamReader;
23 import java.io.OutputStream;
24 import java.io.RandomAccessFile;
25 import java.io.Reader;
26 import java.lang.management.ManagementFactory;
27 import java.nio.charset.Charset;
28 import java.nio.charset.StandardCharsets;
29 import java.nio.file.Files;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.Locale;
33 import java.util.Scanner;
34 import java.util.Set;
35 import java.util.zip.ZipEntry;
36 import java.util.zip.ZipOutputStream;
37
38 import javax.management.MBeanServer;
39 import javax.management.MalformedObjectNameException;
40 import javax.management.ObjectInstance;
41 import javax.management.ObjectName;
42 import javax.servlet.http.HttpServletRequest;
43 import javax.servlet.http.HttpServletResponse;
44
45 import org.codelibs.jhighlight.renderer.Renderer;
46 import org.codelibs.jhighlight.renderer.XhtmlRendererFactory;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 import psiprobe.tokenizer.StringTokenizer;
51 import psiprobe.tokenizer.Token;
52 import psiprobe.tokenizer.Tokenizer;
53 import psiprobe.tokenizer.TokenizerSymbol;
54
55
56
57
58 public final class Utils {
59
60
61 private static final Logger logger = LoggerFactory.getLogger(Utils.class);
62
63
64
65
66 private Utils() {
67
68 }
69
70
71
72
73
74
75
76
77
78
79
80
81 public static String readFile(File file, String charsetName) throws IOException {
82 try (InputStream fis = Files.newInputStream(file.toPath())) {
83 return readStream(fis, charsetName);
84 }
85 }
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102 public static String readStream(InputStream is, String charsetName) throws IOException {
103 Charset charset;
104 if (Charset.isSupported(charsetName)) {
105 charset = Charset.forName(charsetName);
106 } else {
107
108 charset = Charset.defaultCharset();
109 }
110
111 StringBuilder out = new StringBuilder();
112 try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, charset), 4096)) {
113 String line;
114 while ((line = reader.readLine()) != null) {
115 out.append(line).append('\n');
116 }
117 }
118
119 return out.toString();
120 }
121
122
123
124
125
126
127 public static void delete(File file) {
128 if (file != null && file.exists()) {
129 if (file.isDirectory()) {
130 for (File child : file.listFiles()) {
131 delete(child);
132 }
133 }
134 try {
135 Files.delete(file.toPath());
136 } catch (IOException e) {
137 logger.debug("Cannot delete '{}'", file.getAbsolutePath(), e);
138 }
139 } else {
140 logger.debug("'{}' does not exist", file);
141 }
142 }
143
144
145
146
147
148
149
150
151
152 public static int toInt(String num, int defaultValue) {
153 if (num != null && !num.contains(" ")) {
154 try (Scanner scanner = new Scanner(num)) {
155 if (scanner.hasNextInt()) {
156 return scanner.nextInt();
157 }
158 }
159 }
160 return defaultValue;
161 }
162
163
164
165
166
167
168
169
170
171 public static int toIntHex(String num, int defaultValue) {
172 if (num != null && !num.contains(" ")) {
173 if (num.startsWith("#")) {
174 num = num.substring(1);
175 }
176 try (Scanner scanner = new Scanner(num)) {
177 if (scanner.hasNextInt()) {
178 return scanner.nextInt(16);
179 }
180 }
181 }
182 return defaultValue;
183 }
184
185
186
187
188
189
190
191
192
193 public static long toLong(String num, long defaultValue) {
194 if (num != null && !num.contains(" ")) {
195 try (Scanner scanner = new Scanner(num)) {
196 if (scanner.hasNextLong()) {
197 return scanner.nextLong();
198 }
199 }
200 }
201 return defaultValue;
202 }
203
204
205
206
207
208
209
210
211
212 public static long toLong(Long num, long defaultValue) {
213 return num == null ? defaultValue : num;
214 }
215
216
217
218
219
220
221
222
223
224 public static float toFloat(String num, float defaultValue) {
225 if (num != null && !num.contains(" ")) {
226 try (Scanner scanner = new Scanner(num)) {
227 if (scanner.hasNextFloat()) {
228 return scanner.nextFloat();
229 }
230 }
231 }
232 return defaultValue;
233 }
234
235
236
237
238
239
240
241
242
243
244 public static String getJspEncoding(InputStream is) throws IOException {
245
246 String encoding = null;
247 String contentType = null;
248
249 Tokenizer jspTokenizer = new Tokenizer();
250 jspTokenizer.addSymbol("\n", true);
251 jspTokenizer.addSymbol(" ", true);
252 jspTokenizer.addSymbol("\t", true);
253 jspTokenizer.addSymbol(new TokenizerSymbol("dir", "<%@", "%>", false, false, true, false));
254
255 StringTokenizer directiveTokenizer = new StringTokenizer();
256 directiveTokenizer.addSymbol("\n", true);
257 directiveTokenizer.addSymbol(" ", true);
258 directiveTokenizer.addSymbol("\t", true);
259 directiveTokenizer.addSymbol("=");
260 directiveTokenizer.addSymbol("\"", "\"", false);
261 directiveTokenizer.addSymbol("'", "'", false);
262
263 StringTokenizer contentTypeTokenizer = new StringTokenizer();
264 contentTypeTokenizer.addSymbol(" ", true);
265 contentTypeTokenizer.addSymbol(";", true);
266
267 try (Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
268 jspTokenizer.setReader(reader);
269 while (jspTokenizer.hasMore()) {
270 Token token = jspTokenizer.nextToken();
271 if ("dir".equals(token.getName())) {
272 directiveTokenizer.setString(token.getInnerText());
273 if (directiveTokenizer.hasMore()
274 && "page".equals(directiveTokenizer.nextToken().getText())) {
275 while (directiveTokenizer.hasMore()) {
276 Token directiveToken = directiveTokenizer.nextToken();
277 if ("pageEncoding".equals(directiveToken.getText())) {
278 if (directiveTokenizer.hasMore()
279 && "=".equals(directiveTokenizer.nextToken().getText())
280 && directiveTokenizer.hasMore()) {
281 encoding = directiveTokenizer.nextToken().getInnerText();
282 break;
283 }
284 } else if ("contentType".equals(directiveToken.getText())
285 && directiveTokenizer.hasMore()
286 && "=".equals(directiveTokenizer.nextToken().getText())
287 && directiveTokenizer.hasMore()) {
288 contentType = directiveTokenizer.nextToken().getInnerText();
289 }
290 }
291 }
292 }
293 }
294 }
295
296 if (encoding == null && contentType != null) {
297 contentTypeTokenizer.setString(contentType);
298 while (contentTypeTokenizer.hasMore()) {
299 String token = contentTypeTokenizer.nextToken().getText();
300 if (token.startsWith("charset=")) {
301 encoding = token.substring("charset=".length());
302 break;
303 }
304 }
305 }
306
307 return encoding != null ? encoding : StandardCharsets.UTF_8.name();
308 }
309
310
311
312
313
314
315
316
317
318
319 public static void sendFile(HttpServletRequest request, HttpServletResponse response, File file)
320 throws IOException {
321
322 try (OutputStream out = response.getOutputStream();
323 RandomAccessFile raf = new RandomAccessFile(file, "r")) {
324 long fileSize = raf.length();
325 long rangeStart = 0;
326 long rangeFinish = fileSize - 1;
327
328
329 String range = request.getHeader("Range");
330 if (range != null && range.startsWith("bytes=")) {
331 String pureRange = range.replace("bytes=", "");
332 int rangeSep = pureRange.indexOf('-');
333
334 try {
335 rangeStart = Long.parseLong(pureRange.substring(0, rangeSep));
336 if (rangeStart > fileSize || rangeStart < 0) {
337 rangeStart = 0;
338 }
339 } catch (NumberFormatException e) {
340
341 logger.trace("", e);
342 }
343
344 if (rangeSep < pureRange.length() - 1) {
345 try {
346 rangeFinish = Long.parseLong(pureRange.substring(rangeSep + 1));
347 if (rangeFinish < 0 || rangeFinish >= fileSize) {
348 rangeFinish = fileSize - 1;
349 }
350 } catch (NumberFormatException e) {
351 logger.trace("", e);
352 }
353 }
354 }
355
356
357 response.setContentType("application/x-download");
358 response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
359 response.setHeader("Accept-Ranges", "bytes");
360 response.setHeader("Content-Length", Long.toString(rangeFinish - rangeStart + 1));
361 response.setHeader("Content-Range",
362 "bytes " + rangeStart + "-" + rangeFinish + "/" + fileSize);
363
364
365 raf.seek(rangeStart);
366
367
368 byte[] buffer = new byte[4096];
369
370 long len;
371 int totalRead = 0;
372 boolean nomore = false;
373 while (true) {
374 len = raf.read(buffer);
375 if (len > 0 && totalRead + len > rangeFinish - rangeStart + 1) {
376
377
378 len = rangeFinish - rangeStart + 1 - totalRead;
379 nomore = true;
380 }
381
382 if (len <= 0) {
383 break;
384 }
385 out.write(buffer, 0, (int) len);
386 totalRead = totalRead + (int) len;
387 if (nomore) {
388 break;
389 }
390 }
391 }
392 }
393
394
395
396
397
398
399
400
401 public static Thread getThreadByName(String name) {
402 if (name != null) {
403
404 ThreadGroup masterGroup = Thread.currentThread().getThreadGroup();
405 while (masterGroup.getParent() != null) {
406 masterGroup = masterGroup.getParent();
407 }
408
409 Thread[] threads = new Thread[masterGroup.activeCount()];
410 masterGroup.enumerate(threads);
411
412 for (Thread thread : threads) {
413 if (thread != null && name.equals(thread.getName())) {
414 return thread;
415 }
416 }
417 }
418 return null;
419 }
420
421
422
423
424
425
426
427
428
429
430
431
432
433 public static String highlightStream(String name, InputStream input, String rendererName,
434 String encoding) throws IOException {
435
436 Renderer jspRenderer = XhtmlRendererFactory.getRenderer(rendererName);
437 if (jspRenderer == null) {
438 return null;
439 }
440
441 ByteArrayOutputStream bos = new ByteArrayOutputStream();
442 jspRenderer.highlight(name, input, bos, encoding, true);
443
444 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
445
446 Tokenizer tokenizer = new Tokenizer(new InputStreamReader(bis, Charset.forName(encoding)));
447 tokenizer.addSymbol(new TokenizerSymbol("EOL", "\n", null, false, false, true, false));
448 tokenizer.addSymbol(new TokenizerSymbol("EOL", "\r\n", null, false, false, true, false));
449
450
451
452
453
454
455 StringBuilder buffer = new StringBuilder();
456 long counter = 0;
457 while (tokenizer.hasMore()) {
458 Token tk = tokenizer.nextToken();
459 if ("EOL".equals(tk.getName())) {
460 counter++;
461 buffer.append(tk.getText());
462 } else if (counter > 0) {
463 buffer.append("<span class=\"codeline\">");
464 buffer.append("<span class=\"linenum\">");
465 buffer.append(leftPad(Long.toString(counter), 6, " ").replace(" ", " "));
466 buffer.append("</span>");
467 buffer.append(tk.getText());
468 buffer.append("</span>");
469 }
470 }
471 return buffer.toString();
472 }
473
474
475
476
477
478
479
480
481
482 public static void sendCompressedFile(HttpServletResponse response, File file)
483 throws IOException {
484 try (ZipOutputStream zip = new ZipOutputStream(response.getOutputStream());
485 InputStream fileInput = new BufferedInputStream(Files.newInputStream(file.toPath()))) {
486
487 String fileName = file.getName();
488
489
490 response.setContentType("application/zip");
491 response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".zip");
492
493 zip.putNextEntry(new ZipEntry(fileName));
494
495
496 byte[] buffer = new byte[4096];
497 long len;
498
499 while ((len = fileInput.read(buffer)) > 0) {
500 zip.write(buffer, 0, (int) len);
501 }
502 zip.closeEntry();
503 }
504 }
505
506
507
508
509
510
511
512
513
514
515 static String leftPad(final String str, final int len, final String fill) {
516 if (str != null && str.length() < len) {
517 return Strings.padStart(str, len, fill.charAt(0));
518 }
519 return str == null ? "" : str;
520 }
521
522
523
524
525
526
527
528
529
530 public static List<String> getNamesForLocale(String baseName, Locale locale) {
531 List<String> result = new ArrayList<>(3);
532 String language = locale.getLanguage();
533 String country = locale.getCountry();
534 String variant = locale.getVariant();
535 StringBuilder temp = new StringBuilder(baseName);
536
537 if (language.length() > 0) {
538 temp.append('_').append(language);
539 result.add(0, temp.toString());
540 }
541
542 if (country.length() > 0) {
543 temp.append('_').append(country);
544 result.add(0, temp.toString());
545 }
546
547 if (variant.length() > 0) {
548 temp.append('_').append(variant);
549 result.add(0, temp.toString());
550 }
551
552 return result;
553 }
554
555
556
557
558
559
560 public static boolean isThreadingEnabled() {
561 try {
562 MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
563 ObjectName objectNameThreading = new ObjectName("java.lang:type=Threading");
564 Set<ObjectInstance> threading = mbeanServer.queryMBeans(objectNameThreading, null);
565 return threading != null && !threading.isEmpty();
566 } catch (MalformedObjectNameException e) {
567 logger.trace("", e);
568 return false;
569 }
570 }
571 }