001
014
015 package com.liferay.portal.tools.sourceformatter;
016
017 import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
018 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
019 import com.liferay.portal.kernel.util.CharPool;
020 import com.liferay.portal.kernel.util.StringBundler;
021 import com.liferay.portal.kernel.util.StringPool;
022 import com.liferay.portal.kernel.util.StringUtil;
023 import com.liferay.portal.kernel.util.Validator;
024
025 import java.io.File;
026 import java.io.IOException;
027
028 import java.util.ArrayList;
029 import java.util.HashMap;
030 import java.util.HashSet;
031 import java.util.List;
032 import java.util.Map;
033 import java.util.Set;
034 import java.util.regex.Matcher;
035 import java.util.regex.Pattern;
036
037
040 public class JSPSourceProcessor extends BaseSourceProcessor {
041
042 protected void addJSPIncludeFileNames(
043 String fileName, Set<String> includeFileNames) {
044
045 String content = _jspContents.get(fileName);
046
047 if (Validator.isNull(content)) {
048 return;
049 }
050
051 for (int x = 0;;) {
052 x = content.indexOf("<%@ include file=", x);
053
054 if (x == -1) {
055 break;
056 }
057
058 x = content.indexOf(StringPool.QUOTE, x);
059
060 if (x == -1) {
061 break;
062 }
063
064 int y = content.indexOf(StringPool.QUOTE, x + 1);
065
066 if (y == -1) {
067 break;
068 }
069
070 String includeFileName = content.substring(x + 1, y);
071
072 Matcher matcher = _jspIncludeFilePattern.matcher(includeFileName);
073
074 if (!matcher.find()) {
075 throw new RuntimeException(
076 "Invalid include " + includeFileName);
077 }
078
079 String docrootPath = fileName.substring(
080 0, fileName.indexOf("docroot") + 7);
081
082 includeFileName = docrootPath + includeFileName;
083
084 if ((includeFileName.endsWith("jsp") ||
085 includeFileName.endsWith("jspf")) &&
086 !includeFileName.endsWith("html/portlet/init.jsp") &&
087 !includeFileName.endsWith("html/taglib/init.jsp") &&
088 !includeFileNames.contains(includeFileName)) {
089
090 includeFileNames.add(includeFileName);
091 }
092
093 x = y;
094 }
095 }
096
097 protected void addJSPReferenceFileNames(
098 String fileName, Set<String> includeFileNames) {
099
100 for (Map.Entry<String, String> entry : _jspContents.entrySet()) {
101 String referenceFileName = entry.getKey();
102 String content = entry.getValue();
103
104 if (content.contains("<%@ include file=\"" + fileName) &&
105 !includeFileNames.contains(referenceFileName)) {
106
107 includeFileNames.add(referenceFileName);
108 }
109 }
110 }
111
112 protected void addJSPUnusedImports(
113 String fileName, List<String> importLines,
114 List<String> unneededImports) {
115
116 for (String importLine : importLines) {
117 Set<String> includeFileNames = new HashSet<String>();
118
119 includeFileNames.add(fileName);
120
121 Set<String> checkedFileNames = new HashSet<String>();
122
123 int x = importLine.indexOf(StringPool.QUOTE);
124 int y = importLine.indexOf(StringPool.QUOTE, x + 1);
125
126 if ((x == -1) || (y == -1)) {
127 continue;
128 }
129
130 String className = importLine.substring(x + 1, y);
131
132 className = className.substring(
133 className.lastIndexOf(StringPool.PERIOD) + 1);
134
135 if (!isClassOrVariableRequired(
136 fileName, className, includeFileNames, checkedFileNames)) {
137
138 unneededImports.add(importLine);
139 }
140 }
141 }
142
143 protected boolean checkTaglibVulnerability(
144 String jspContent, String vulnerability) {
145
146 int pos1 = -1;
147
148 do {
149 pos1 = jspContent.indexOf(vulnerability, pos1 + 1);
150
151 if (pos1 != -1) {
152 int pos2 = jspContent.lastIndexOf(CharPool.LESS_THAN, pos1);
153
154 while ((pos2 > 0) &&
155 (jspContent.charAt(pos2 + 1) == CharPool.PERCENT)) {
156
157 pos2 = jspContent.lastIndexOf(CharPool.LESS_THAN, pos2 - 1);
158 }
159
160 String tagContent = jspContent.substring(pos2, pos1);
161
162 if (!tagContent.startsWith("<aui:") &&
163 !tagContent.startsWith("<liferay-portlet:") &&
164 !tagContent.startsWith("<liferay-util:") &&
165 !tagContent.startsWith("<portlet:")) {
166
167 return true;
168 }
169 }
170 }
171 while (pos1 != -1);
172
173 return false;
174 }
175
176 protected void checkXSS(String fileName, String jspContent) {
177 Matcher matcher = _xssPattern.matcher(jspContent);
178
179 while (matcher.find()) {
180 boolean xssVulnerable = false;
181
182 String jspVariable = matcher.group(1);
183
184 String anchorVulnerability = " href=\"<%= " + jspVariable + " %>";
185
186 if (checkTaglibVulnerability(jspContent, anchorVulnerability)) {
187 xssVulnerable = true;
188 }
189
190 String inputVulnerability = " value=\"<%= " + jspVariable + " %>";
191
192 if (checkTaglibVulnerability(jspContent, inputVulnerability)) {
193 xssVulnerable = true;
194 }
195
196 String inlineStringVulnerability1 = "'<%= " + jspVariable + " %>";
197
198 if (jspContent.contains(inlineStringVulnerability1)) {
199 xssVulnerable = true;
200 }
201
202 String inlineStringVulnerability2 = "(\"<%= " + jspVariable + " %>";
203
204 if (jspContent.contains(inlineStringVulnerability2)) {
205 xssVulnerable = true;
206 }
207
208 String inlineStringVulnerability3 = " \"<%= " + jspVariable + " %>";
209
210 if (jspContent.contains(inlineStringVulnerability3)) {
211 xssVulnerable = true;
212 }
213
214 String documentIdVulnerability = ".<%= " + jspVariable + " %>";
215
216 if (jspContent.contains(documentIdVulnerability)) {
217 xssVulnerable = true;
218 }
219
220 if (xssVulnerable) {
221 processErrorMessage(
222 fileName, "(xss): " + fileName + " (" + jspVariable + ")");
223 }
224 }
225 }
226
227 @Override
228 protected void format() throws Exception {
229 String[] excludes = new String[] {
230 "**\\portal\\aui\\**", "**\\bin\\**", "**\\null.jsp", "**\\tmp\\**",
231 "**\\tools\\**"
232 };
233 String[] includes = new String[] {
234 "**\\*.jsp", "**\\*.jspf", "**\\*.vm"
235 };
236
237 List<String> fileNames = getFileNames(excludes, includes);
238
239 for (String fileName : fileNames) {
240 File file = new File(BASEDIR + fileName);
241
242 fileName = StringUtil.replace(
243 fileName, StringPool.BACK_SLASH, StringPool.SLASH);
244
245 String content = fileUtil.read(file);
246
247 _jspContents.put(fileName, content);
248 }
249
250 for (String fileName : fileNames) {
251 format(fileName);
252 }
253 }
254
255 @Override
256 protected String format(String fileName) throws Exception {
257 File file = new File(BASEDIR + fileName);
258
259 fileName = StringUtil.replace(
260 fileName, StringPool.BACK_SLASH, StringPool.SLASH);
261
262 String content = fileUtil.read(file);
263
264 String oldContent = content;
265 String newContent = StringPool.BLANK;
266
267 while (true) {
268 newContent = formatJSP(fileName, oldContent);
269
270 if (oldContent.equals(newContent)) {
271 break;
272 }
273
274 oldContent = newContent;
275 }
276
277 newContent = StringUtil.replace(
278 newContent,
279 new String[] {
280 "<br/>", "\"/>", "\" >", "@page import", "\"%>", ")%>", "else{",
281 "for(", "function (", "if(", "javascript: ", "while(", "){\n",
282 "\n\n\n"
283 },
284 new String[] {
285 "<br />", "\" />", "\">", "@ page import", "\" %>", ") %>",
286 "else {", "for (", "function(", "if (", "javascript:",
287 "while (", ") {\n", "\n\n"
288 });
289
290 newContent = fixCompatClassImports(file, newContent);
291
292 if (_stripJSPImports && !_jspContents.isEmpty()) {
293 try {
294 newContent = stripJSPImports(fileName, newContent);
295 }
296 catch (RuntimeException re) {
297 _stripJSPImports = false;
298 }
299 }
300
301 newContent = fixCopyright(
302 newContent, getCopyright(), getOldCopyright(), file, fileName);
303
304 newContent = StringUtil.replace(
305 newContent,
306 new String[] {
307 "alert('<%= LanguageUtil.", "alert(\"<%= LanguageUtil.",
308 "confirm('<%= LanguageUtil.", "confirm(\"<%= LanguageUtil."
309 },
310 new String[] {
311 "alert('<%= UnicodeLanguageUtil.",
312 "alert(\"<%= UnicodeLanguageUtil.",
313 "confirm('<%= UnicodeLanguageUtil.",
314 "confirm(\"<%= UnicodeLanguageUtil."
315 });
316
317 if (newContent.contains(" ")) {
318 if (!fileName.matches(".*template.*\\.vm$")) {
319 processErrorMessage(fileName, "tab: " + fileName);
320 }
321 }
322
323 if (fileName.endsWith("init.jsp") || fileName.endsWith("init.jspf")) {
324 int x = newContent.indexOf("<%@ page import=");
325
326 int y = newContent.lastIndexOf("<%@ page import=");
327
328 y = newContent.indexOf("%>", y);
329
330 if ((x != -1) && (y != -1) && (y > x)) {
331
332
333
334 boolean compressImports = true;
335
336 if (compressImports) {
337 String imports = newContent.substring(x, y);
338
339 imports = StringUtil.replace(
340 imports, new String[] {"%>\r\n<%@ ", "%>\n<%@ "},
341 new String[] {"%><%@\r\n", "%><%@\n"});
342
343 newContent =
344 newContent.substring(0, x) + imports +
345 newContent.substring(y);
346 }
347 }
348 }
349
350 newContent = fixSessionKey(fileName, newContent, sessionKeyPattern);
351 newContent = fixSessionKey(
352 fileName, newContent, taglibSessionKeyPattern);
353
354 checkLanguageKeys(fileName, newContent, languageKeyPattern);
355 checkLanguageKeys(fileName, newContent, _taglibLanguageKeyPattern);
356 checkXSS(fileName, newContent);
357
358 if (isAutoFix() && (newContent != null) &&
359 !content.equals(newContent)) {
360
361 fileUtil.write(file, newContent);
362
363 sourceFormatterHelper.printError(fileName, file);
364 }
365
366 return newContent;
367 }
368
369 protected String formatJSP(String fileName, String content)
370 throws IOException {
371
372 StringBundler sb = new StringBundler();
373
374 UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
375 new UnsyncStringReader(content));
376
377 int lineCount = 0;
378
379 String line = null;
380
381 String previousLine = StringPool.BLANK;
382
383 String currentAttributeAndValue = null;
384 String previousAttribute = null;
385 String previousAttributeAndValue = null;
386
387 boolean readAttributes = false;
388
389 String currentException = null;
390 String previousException = null;
391
392 boolean hasUnsortedExceptions = false;
393
394 boolean javaSource = false;
395
396 while ((line = unsyncBufferedReader.readLine()) != null) {
397 lineCount++;
398
399 if (!fileName.contains("jsonw") ||
400 !fileName.endsWith("action.jsp")) {
401
402 line = trimLine(line, false);
403 }
404
405 if (line.contains("<aui:button ") &&
406 line.contains("type=\"button\"")) {
407
408 processErrorMessage(
409 fileName, "aui:button " + fileName + " " + lineCount);
410 }
411
412 String trimmedLine = StringUtil.trimLeading(line);
413 String trimmedPreviousLine = StringUtil.trimLeading(previousLine);
414
415 checkStringBundler(trimmedLine, fileName, lineCount);
416
417 if (trimmedLine.equals("<%") || trimmedLine.equals("<%!")) {
418 javaSource = true;
419 }
420 else if (trimmedLine.equals("%>")) {
421 javaSource = false;
422 }
423
424 if (javaSource || trimmedLine.contains("<%= ")) {
425 checkInefficientStringMethods(line, fileName, lineCount);
426 }
427
428 if (javaSource && portalSource && !_jspContents.isEmpty() &&
429 hasUnusedVariable(fileName, trimmedLine)) {
430
431 processErrorMessage(
432 fileName, "Unused variable: " + fileName + " " + lineCount);
433 }
434
435 if (!trimmedLine.equals("%>") && line.contains("%>") &&
436 !line.contains("--%>") && !line.contains(" %>")) {
437
438 line = StringUtil.replace(line, "%>", " %>");
439 }
440
441 if (line.contains("<%=") && !line.contains("<%= ")) {
442 line = StringUtil.replace(line, "<%=", "<%= ");
443 }
444
445 if (trimmedPreviousLine.equals("%>") && Validator.isNotNull(line) &&
446 !trimmedLine.equals("-->")) {
447
448 sb.append("\n");
449 }
450 else if (Validator.isNotNull(previousLine) &&
451 !trimmedPreviousLine.equals("<!--") &&
452 trimmedLine.equals("<%")) {
453
454 sb.append("\n");
455 }
456 else if (trimmedPreviousLine.equals("<%") &&
457 Validator.isNull(line)) {
458
459 continue;
460 }
461 else if (trimmedPreviousLine.equals("<%") &&
462 trimmedLine.startsWith("
463
464 sb.append("\n");
465 }
466 else if (Validator.isNull(previousLine) &&
467 trimmedLine.equals("%>") && (sb.index() > 2)) {
468
469 String lineBeforePreviousLine = sb.stringAt(sb.index() - 3);
470
471 if (!lineBeforePreviousLine.startsWith("
472 sb.setIndex(sb.index() - 1);
473 }
474 }
475
476 if ((trimmedLine.startsWith("if (") ||
477 trimmedLine.startsWith("else if (") ||
478 trimmedLine.startsWith("while (")) &&
479 trimmedLine.endsWith(") {")) {
480
481 checkIfClauseParentheses(trimmedLine, fileName, lineCount);
482 }
483
484 if (readAttributes) {
485 if (!trimmedLine.startsWith(StringPool.FORWARD_SLASH) &&
486 !trimmedLine.startsWith(StringPool.GREATER_THAN)) {
487
488 int pos = trimmedLine.indexOf(StringPool.EQUAL);
489
490 if (pos != -1) {
491 String attribute = trimmedLine.substring(0, pos);
492
493 if (!trimmedLine.endsWith(StringPool.QUOTE) &&
494 !trimmedLine.endsWith(StringPool.APOSTROPHE)) {
495
496 processErrorMessage(
497 fileName,
498 "attribute: " + fileName + " " + lineCount);
499
500 readAttributes = false;
501 }
502 else if (trimmedLine.endsWith(StringPool.APOSTROPHE) &&
503 !trimmedLine.contains(StringPool.QUOTE)) {
504
505 line = StringUtil.replace(
506 line, StringPool.APOSTROPHE, StringPool.QUOTE);
507
508 readAttributes = false;
509 }
510 else if (Validator.isNotNull(previousAttribute)) {
511 if (!isJSPAttributName(attribute)) {
512 processErrorMessage(
513 fileName,
514 "attribute: " + fileName + " " + lineCount);
515
516 readAttributes = false;
517 }
518 else if (Validator.isNull(
519 previousAttributeAndValue) &&
520 (previousAttribute.compareTo(
521 attribute) > 0)) {
522
523 previousAttributeAndValue = previousLine;
524 currentAttributeAndValue = line;
525 }
526 }
527
528 if (!readAttributes) {
529 previousAttribute = null;
530 previousAttributeAndValue = null;
531 }
532 else {
533 previousAttribute = attribute;
534 }
535 }
536 }
537 else {
538 previousAttribute = null;
539
540 readAttributes = false;
541 }
542 }
543
544 if (!hasUnsortedExceptions) {
545 int i = line.indexOf("<liferay-ui:error exception=\"<%=");
546
547 if (i != -1) {
548 currentException = line.substring(i + 33);
549
550 if (Validator.isNotNull(previousException) &&
551 (previousException.compareTo(currentException) > 0)) {
552
553 hasUnsortedExceptions = true;
554 }
555 }
556
557 if (!hasUnsortedExceptions) {
558 previousException = currentException;
559 currentException = null;
560 }
561 }
562
563 if (trimmedLine.startsWith(StringPool.LESS_THAN) &&
564 !trimmedLine.startsWith("<%") &&
565 !trimmedLine.startsWith("<!")) {
566
567 if (!trimmedLine.contains(StringPool.GREATER_THAN) &&
568 !trimmedLine.contains(StringPool.SPACE)) {
569
570 readAttributes = true;
571 }
572 else {
573 line = sortJSPAttributes(fileName, line, lineCount);
574 }
575 }
576
577 if (!trimmedLine.contains(StringPool.DOUBLE_SLASH) &&
578 !trimmedLine.startsWith(StringPool.STAR)) {
579
580 while (trimmedLine.contains(StringPool.TAB)) {
581 line = StringUtil.replaceLast(
582 line, StringPool.TAB, StringPool.SPACE);
583
584 trimmedLine = StringUtil.replaceLast(
585 trimmedLine, StringPool.TAB, StringPool.SPACE);
586 }
587
588 while (trimmedLine.contains(StringPool.DOUBLE_SPACE) &&
589 !trimmedLine.contains(
590 StringPool.QUOTE + StringPool.DOUBLE_SPACE) &&
591 !fileName.endsWith(".vm")) {
592
593 line = StringUtil.replaceLast(
594 line, StringPool.DOUBLE_SPACE, StringPool.SPACE);
595
596 trimmedLine = StringUtil.replaceLast(
597 trimmedLine, StringPool.DOUBLE_SPACE, StringPool.SPACE);
598 }
599 }
600
601 if (!fileName.endsWith("/touch.jsp")) {
602 int x = line.indexOf("<%@ include file");
603
604 if (x != -1) {
605 x = line.indexOf(StringPool.QUOTE, x);
606
607 int y = line.indexOf(StringPool.QUOTE, x + 1);
608
609 if (y != -1) {
610 String includeFileName = line.substring(x + 1, y);
611
612 Matcher matcher = _jspIncludeFilePattern.matcher(
613 includeFileName);
614
615 if (!matcher.find()) {
616 processErrorMessage(
617 fileName,
618 "include: " + fileName + " " + lineCount);
619 }
620 }
621 }
622 }
623
624 line = replacePrimitiveWrapperInstantiation(
625 fileName, line, lineCount);
626
627 previousLine = line;
628
629 sb.append(line);
630 sb.append("\n");
631 }
632
633 unsyncBufferedReader.close();
634
635 content = sb.toString();
636
637 if (content.endsWith("\n")) {
638 content = content.substring(0, content.length() - 1);
639 }
640
641 content = formatTaglibQuotes(fileName, content, StringPool.QUOTE);
642 content = formatTaglibQuotes(fileName, content, StringPool.APOSTROPHE);
643
644 if (Validator.isNotNull(previousAttributeAndValue)) {
645 content = StringUtil.replaceFirst(
646 content,
647 previousAttributeAndValue + "\n" + currentAttributeAndValue,
648 currentAttributeAndValue + "\n" + previousAttributeAndValue);
649 }
650
651 if (hasUnsortedExceptions) {
652 if ((StringUtil.count(content, currentException) > 1) ||
653 (StringUtil.count(content, previousException) > 1)) {
654
655 processErrorMessage(
656 fileName, "unsorted exceptions: " + fileName);
657 }
658 else {
659 content = StringUtil.replaceFirst(
660 content, previousException, currentException);
661
662 content = StringUtil.replaceLast(
663 content, currentException, previousException);
664 }
665 }
666
667 return content;
668 }
669
670 protected String formatTaglibQuotes(
671 String fileName, String content, String quoteType) {
672
673 String quoteFix = StringPool.APOSTROPHE;
674
675 if (quoteFix.equals(quoteType)) {
676 quoteFix = StringPool.QUOTE;
677 }
678
679 Pattern pattern = Pattern.compile(getTaglibRegex(quoteType));
680
681 Matcher matcher = pattern.matcher(content);
682
683 while (matcher.find()) {
684 int x = content.indexOf(quoteType + "<%=", matcher.start());
685 int y = content.indexOf("%>" + quoteType, x);
686
687 while ((x != -1) && (y != -1)) {
688 String result = content.substring(x + 1, y + 2);
689
690 if (result.contains(quoteType)) {
691 int lineCount = 1;
692
693 char[] contentCharArray = content.toCharArray();
694
695 for (int i = 0; i < x; i++) {
696 if (contentCharArray[i] == CharPool.NEW_LINE) {
697 lineCount++;
698 }
699 }
700
701 if (!result.contains(quoteFix)) {
702 StringBundler sb = new StringBundler(5);
703
704 sb.append(content.substring(0, x));
705 sb.append(quoteFix);
706 sb.append(result);
707 sb.append(quoteFix);
708 sb.append(content.substring(y + 3, content.length()));
709
710 content = sb.toString();
711 }
712 else {
713 processErrorMessage(
714 fileName, "taglib: " + fileName + " " + lineCount);
715 }
716 }
717
718 x = content.indexOf(quoteType + "<%=", y);
719
720 if (x > matcher.end()) {
721 break;
722 }
723
724 y = content.indexOf("%>" + quoteType, x);
725 }
726 }
727
728 return content;
729 }
730
731 protected List<String> getJSPDuplicateImports(
732 String fileName, String content, List<String> importLines) {
733
734 List<String> duplicateImports = new ArrayList<String>();
735
736 for (String importLine : importLines) {
737 int x = content.indexOf("<%@ include file=");
738
739 if (x == -1) {
740 continue;
741 }
742
743 int y = content.indexOf("<%@ page import=");
744
745 if (y == -1) {
746 continue;
747 }
748
749 if ((x < y) && isJSPDuplicateImport(fileName, importLine, false)) {
750 duplicateImports.add(importLine);
751 }
752 }
753
754 return duplicateImports;
755 }
756
757 protected String getTaglibRegex(String quoteType) {
758 StringBuilder sb = new StringBuilder();
759
760 sb.append("<(");
761
762 for (int i = 0; i < _TAG_LIBRARIES.length; i++) {
763 sb.append(_TAG_LIBRARIES[i]);
764 sb.append(StringPool.PIPE);
765 }
766
767 sb.deleteCharAt(sb.length() - 1);
768 sb.append("):([^>]|%>)*");
769 sb.append(quoteType);
770 sb.append("<%=.*");
771 sb.append(quoteType);
772 sb.append(".*%>");
773 sb.append(quoteType);
774 sb.append("([^>]|%>)*>");
775
776 return sb.toString();
777 }
778
779 protected String getVariableName(String line) {
780 if (!line.endsWith(";") || line.startsWith("
781 return null;
782 }
783
784 String variableName = null;
785
786 int x = line.indexOf(" = ");
787
788 if (x == -1) {
789 int y = line.lastIndexOf(" ");
790
791 if (y != -1) {
792 variableName = line.substring(y + 1, line.length() - 1);
793 }
794 }
795 else {
796 line = line.substring(0, x);
797
798 int y = line.lastIndexOf(" ");
799
800 if (y != -1) {
801 variableName = line.substring(y + 1);
802 }
803 }
804
805 if (Validator.isVariableName(variableName)) {
806 return variableName;
807 }
808
809 return null;
810 }
811
812 protected boolean hasUnusedVariable(String fileName, String line) {
813 if (line.contains(": ")) {
814 return false;
815 }
816
817 String variableName = getVariableName(line);
818
819 if (Validator.isNull(variableName) || variableName.equals("false") ||
820 variableName.equals("true")) {
821
822 return false;
823 }
824
825 Set<String> includeFileNames = new HashSet<String>();
826
827 includeFileNames.add(fileName);
828
829 Set<String> checkedFileNames = new HashSet<String>();
830
831 return !isClassOrVariableRequired(
832 fileName, variableName, includeFileNames, checkedFileNames);
833 }
834
835 protected boolean isClassOrVariableRequired(
836 String fileName, String name, Set<String> includeFileNames,
837 Set<String> checkedFileNames) {
838
839 if (checkedFileNames.contains(fileName)) {
840 return false;
841 }
842
843 checkedFileNames.add(fileName);
844
845 String content = _jspContents.get(fileName);
846
847 if (Validator.isNull(content)) {
848 return false;
849 }
850
851 Pattern pattern = Pattern.compile(
852 "[^A-Za-z0-9_]" + name + "[^A-Za-z0-9_]");
853
854 Matcher matcher = pattern.matcher(content);
855
856 if (matcher.find() &&
857 ((checkedFileNames.size() > 1) || matcher.find())) {
858
859 return true;
860 }
861
862 addJSPIncludeFileNames(fileName, includeFileNames);
863
864 String docrootPath = fileName.substring(
865 0, fileName.indexOf("docroot") + 7);
866
867 fileName = fileName.replaceFirst(docrootPath, StringPool.BLANK);
868
869 if (fileName.endsWith("init.jsp") || fileName.endsWith("init.jspf") ||
870 fileName.contains("init-ext.jsp")) {
871
872 addJSPReferenceFileNames(fileName, includeFileNames);
873 }
874
875 String[] includeFileNamesArray = includeFileNames.toArray(
876 new String[includeFileNames.size()]);
877
878 for (String includeFileName : includeFileNamesArray) {
879 if (!checkedFileNames.contains(includeFileName) &&
880 isClassOrVariableRequired(
881 includeFileName, name, includeFileNames,
882 checkedFileNames)) {
883
884 return true;
885 }
886 }
887
888 return false;
889 }
890
891 protected boolean isJSPAttributName(String attributeName) {
892 if (Validator.isNull(attributeName)) {
893 return false;
894 }
895
896 Matcher matcher = _jspAttributeNamePattern.matcher(attributeName);
897
898 return matcher.matches();
899 }
900
901 protected boolean isJSPDuplicateImport(
902 String fileName, String importLine, boolean checkFile) {
903
904 String content = _jspContents.get(fileName);
905
906 if (Validator.isNull(content)) {
907 return false;
908 }
909
910 int x = importLine.indexOf("page");
911
912 if (x == -1) {
913 return false;
914 }
915
916 if (checkFile && content.contains(importLine.substring(x))) {
917 return true;
918 }
919
920 int y = content.indexOf("<%@ include file=");
921
922 if (y == -1) {
923 return false;
924 }
925
926 y = content.indexOf(StringPool.QUOTE, y);
927
928 if (y == -1) {
929 return false;
930 }
931
932 int z = content.indexOf(StringPool.QUOTE, y + 1);
933
934 if (z == -1) {
935 return false;
936 }
937
938 String includeFileName = content.substring(y + 1, z);
939
940 String docrootPath = fileName.substring(
941 0, fileName.indexOf("docroot") + 7);
942
943 includeFileName = docrootPath + includeFileName;
944
945 return isJSPDuplicateImport(includeFileName, importLine, true);
946 }
947
948 protected String sortJSPAttributes(
949 String fileName, String line, int lineCount) {
950
951 String s = line;
952
953 int x = s.indexOf(StringPool.SPACE);
954
955 if (x == -1) {
956 return line;
957 }
958
959 s = s.substring(x + 1);
960
961 String previousAttribute = null;
962 String previousAttributeAndValue = null;
963
964 boolean wrongOrder = false;
965
966 for (x = 0;;) {
967 x = s.indexOf(StringPool.EQUAL);
968
969 if ((x == -1) || (s.length() <= (x + 1))) {
970 return line;
971 }
972
973 String attribute = s.substring(0, x);
974
975 if (!isJSPAttributName(attribute)) {
976 return line;
977 }
978
979 if (Validator.isNotNull(previousAttribute) &&
980 (previousAttribute.compareTo(attribute) > 0)) {
981
982 wrongOrder = true;
983 }
984
985 s = s.substring(x + 1);
986
987 char delimeter = s.charAt(0);
988
989 if ((delimeter != CharPool.APOSTROPHE) &&
990 (delimeter != CharPool.QUOTE)) {
991
992 processErrorMessage(
993 fileName, "delimeter: " + fileName + " " + lineCount);
994
995 return line;
996 }
997
998 s = s.substring(1);
999
1000 String value = null;
1001
1002 int y = -1;
1003
1004 while (true) {
1005 y = s.indexOf(delimeter, y + 1);
1006
1007 if ((y == -1) || (s.length() <= (y + 1))) {
1008 return line;
1009 }
1010
1011 value = s.substring(0, y);
1012
1013 if (value.startsWith("<%")) {
1014 int endJavaCodeSignCount = StringUtil.count(value, "%>");
1015 int startJavaCodeSignCount = StringUtil.count(value, "<%");
1016
1017 if (endJavaCodeSignCount == startJavaCodeSignCount) {
1018 break;
1019 }
1020 }
1021 else {
1022 int greaterThanCount = StringUtil.count(
1023 value, StringPool.GREATER_THAN);
1024 int lessThanCount = StringUtil.count(
1025 value, StringPool.LESS_THAN);
1026
1027 if (greaterThanCount == lessThanCount) {
1028 break;
1029 }
1030 }
1031 }
1032
1033 if ((delimeter == CharPool.APOSTROPHE) &&
1034 !value.contains(StringPool.QUOTE)) {
1035
1036 return StringUtil.replace(
1037 line, StringPool.APOSTROPHE + value + StringPool.APOSTROPHE,
1038 StringPool.QUOTE + value + StringPool.QUOTE);
1039 }
1040
1041 StringBundler sb = new StringBundler(5);
1042
1043 sb.append(attribute);
1044 sb.append(StringPool.EQUAL);
1045 sb.append(delimeter);
1046 sb.append(value);
1047 sb.append(delimeter);
1048
1049 String currentAttributeAndValue = sb.toString();
1050
1051 if (wrongOrder) {
1052 if ((StringUtil.count(line, currentAttributeAndValue) == 1) &&
1053 (StringUtil.count(line, previousAttributeAndValue) == 1)) {
1054
1055 line = StringUtil.replaceFirst(
1056 line, previousAttributeAndValue,
1057 currentAttributeAndValue);
1058
1059 line = StringUtil.replaceLast(
1060 line, currentAttributeAndValue,
1061 previousAttributeAndValue);
1062 }
1063
1064 return line;
1065 }
1066
1067 s = s.substring(y + 1);
1068
1069 s = StringUtil.trimLeading(s);
1070
1071 previousAttribute = attribute;
1072 previousAttributeAndValue = currentAttributeAndValue;
1073 }
1074 }
1075
1076 protected String stripJSPImports(String fileName, String content)
1077 throws IOException {
1078
1079 fileName = fileName.replace(
1080 CharPool.BACK_SLASH, CharPool.FORWARD_SLASH);
1081
1082 if (!fileName.contains("docroot") ||
1083 fileName.endsWith("init-ext.jsp")) {
1084
1085 return content;
1086 }
1087
1088 Matcher matcher = _jspImportPattern.matcher(content);
1089
1090 if (!matcher.find()) {
1091 return content;
1092 }
1093
1094 String imports = matcher.group();
1095
1096 imports = StringUtil.replace(
1097 imports, new String[] {"%><%@\r\n", "%><%@\n"},
1098 new String[] {"%>\r\n<%@ ", "%>\n<%@ "});
1099
1100 if (!fileName.endsWith("html/common/init.jsp") &&
1101 !fileName.endsWith("html/portal/init.jsp")) {
1102
1103 List<String> importLines = new ArrayList<String>();
1104
1105 UnsyncBufferedReader unsyncBufferedReader =
1106 new UnsyncBufferedReader(new UnsyncStringReader(imports));
1107
1108 String line = null;
1109
1110 while ((line = unsyncBufferedReader.readLine()) != null) {
1111 if (line.contains("import=")) {
1112 importLines.add(line);
1113 }
1114 }
1115
1116 List<String> unneededImports = getJSPDuplicateImports(
1117 fileName, content, importLines);
1118
1119 addJSPUnusedImports(fileName, importLines, unneededImports);
1120
1121 for (String unneededImport : unneededImports) {
1122 imports = StringUtil.replace(
1123 imports, unneededImport, StringPool.BLANK);
1124 }
1125 }
1126
1127 imports = formatImports(imports, 17);
1128
1129 String beforeImports = content.substring(0, matcher.start());
1130
1131 if (Validator.isNull(imports)) {
1132 beforeImports = StringUtil.replaceLast(
1133 beforeImports, "\n", StringPool.BLANK);
1134 }
1135
1136 String afterImports = content.substring(matcher.end());
1137
1138 if (Validator.isNull(afterImports)) {
1139 imports = StringUtil.replaceLast(imports, "\n", StringPool.BLANK);
1140
1141 content = beforeImports + imports;
1142
1143 return content;
1144 }
1145
1146 content = beforeImports + imports + "\n" + afterImports;
1147
1148 return content;
1149 }
1150
1151 private static final String[] _TAG_LIBRARIES = new String[] {
1152 "aui", "c", "html", "jsp", "liferay-portlet", "liferay-security",
1153 "liferay-theme", "liferay-ui", "liferay-util", "portlet", "struts",
1154 "tiles"
1155 };
1156
1157 private Pattern _jspAttributeNamePattern = Pattern.compile(
1158 "[a-z]+[-_a-zA-Z0-9]*");
1159 private Map<String, String> _jspContents = new HashMap<String, String>();
1160 private Pattern _jspImportPattern = Pattern.compile(
1161 "(<.*\n*page.import=\".*>\n*)+", Pattern.MULTILINE);
1162 private Pattern _jspIncludeFilePattern = Pattern.compile("/.*[.]jsp[f]?");
1163 private boolean _stripJSPImports = true;
1164 private Pattern _taglibLanguageKeyPattern = Pattern.compile(
1165 "(?:confirmation|label|(?:M|m)essage|message key|names|title)=\"[^A-Z" +
1166 "<=%\\[\\s]+\"");
1167 private Pattern _xssPattern = Pattern.compile(
1168 "\\s+([^\\s]+)\\s*=\\s*(Bean)?ParamUtil\\.getString\\(");
1169
1170 }