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 && portalSource && !_jspContents.isEmpty() &&
425 hasUnusedVariable(fileName, trimmedLine)) {
426
427 processErrorMessage(
428 fileName, "Unused variable: " + fileName + " " + lineCount);
429 }
430
431 if (!trimmedLine.equals("%>") && line.contains("%>") &&
432 !line.contains("--%>") && !line.contains(" %>")) {
433
434 line = StringUtil.replace(line, "%>", " %>");
435 }
436
437 if (line.contains("<%=") && !line.contains("<%= ")) {
438 line = StringUtil.replace(line, "<%=", "<%= ");
439 }
440
441 if (trimmedPreviousLine.equals("%>") && Validator.isNotNull(line) &&
442 !trimmedLine.equals("-->")) {
443
444 sb.append("\n");
445 }
446 else if (Validator.isNotNull(previousLine) &&
447 !trimmedPreviousLine.equals("<!--") &&
448 trimmedLine.equals("<%")) {
449
450 sb.append("\n");
451 }
452 else if (trimmedPreviousLine.equals("<%") &&
453 Validator.isNull(line)) {
454
455 continue;
456 }
457 else if (trimmedPreviousLine.equals("<%") &&
458 trimmedLine.startsWith("
459
460 sb.append("\n");
461 }
462 else if (Validator.isNull(previousLine) &&
463 trimmedLine.equals("%>") && (sb.index() > 2)) {
464
465 String lineBeforePreviousLine = sb.stringAt(sb.index() - 3);
466
467 if (!lineBeforePreviousLine.startsWith("
468 sb.setIndex(sb.index() - 1);
469 }
470 }
471
472 if ((trimmedLine.startsWith("if (") ||
473 trimmedLine.startsWith("else if (") ||
474 trimmedLine.startsWith("while (")) &&
475 trimmedLine.endsWith(") {")) {
476
477 checkIfClauseParentheses(trimmedLine, fileName, lineCount);
478 }
479
480 if (readAttributes) {
481 if (!trimmedLine.startsWith(StringPool.FORWARD_SLASH) &&
482 !trimmedLine.startsWith(StringPool.GREATER_THAN)) {
483
484 int pos = trimmedLine.indexOf(StringPool.EQUAL);
485
486 if (pos != -1) {
487 String attribute = trimmedLine.substring(0, pos);
488
489 if (!trimmedLine.endsWith(StringPool.QUOTE) &&
490 !trimmedLine.endsWith(StringPool.APOSTROPHE)) {
491
492 processErrorMessage(
493 fileName,
494 "attribute: " + fileName + " " + lineCount);
495
496 readAttributes = false;
497 }
498 else if (trimmedLine.endsWith(StringPool.APOSTROPHE) &&
499 !trimmedLine.contains(StringPool.QUOTE)) {
500
501 line = StringUtil.replace(
502 line, StringPool.APOSTROPHE, StringPool.QUOTE);
503
504 readAttributes = false;
505 }
506 else if (Validator.isNotNull(previousAttribute)) {
507 if (!isJSPAttributName(attribute)) {
508 processErrorMessage(
509 fileName,
510 "attribute: " + fileName + " " + lineCount);
511
512 readAttributes = false;
513 }
514 else if (Validator.isNull(
515 previousAttributeAndValue) &&
516 (previousAttribute.compareTo(
517 attribute) > 0)) {
518
519 previousAttributeAndValue = previousLine;
520 currentAttributeAndValue = line;
521 }
522 }
523
524 if (!readAttributes) {
525 previousAttribute = null;
526 previousAttributeAndValue = null;
527 }
528 else {
529 previousAttribute = attribute;
530 }
531 }
532 }
533 else {
534 previousAttribute = null;
535
536 readAttributes = false;
537 }
538 }
539
540 if (!hasUnsortedExceptions) {
541 int i = line.indexOf("<liferay-ui:error exception=\"<%=");
542
543 if (i != -1) {
544 currentException = line.substring(i + 33);
545
546 if (Validator.isNotNull(previousException) &&
547 (previousException.compareTo(currentException) > 0)) {
548
549 hasUnsortedExceptions = true;
550 }
551 }
552
553 if (!hasUnsortedExceptions) {
554 previousException = currentException;
555 currentException = null;
556 }
557 }
558
559 if (trimmedLine.startsWith(StringPool.LESS_THAN) &&
560 !trimmedLine.startsWith("<%") &&
561 !trimmedLine.startsWith("<!")) {
562
563 if (!trimmedLine.contains(StringPool.GREATER_THAN) &&
564 !trimmedLine.contains(StringPool.SPACE)) {
565
566 readAttributes = true;
567 }
568 else {
569 line = sortJSPAttributes(fileName, line, lineCount);
570 }
571 }
572
573 if (!trimmedLine.contains(StringPool.DOUBLE_SLASH) &&
574 !trimmedLine.startsWith(StringPool.STAR)) {
575
576 while (trimmedLine.contains(StringPool.TAB)) {
577 line = StringUtil.replaceLast(
578 line, StringPool.TAB, StringPool.SPACE);
579
580 trimmedLine = StringUtil.replaceLast(
581 trimmedLine, StringPool.TAB, StringPool.SPACE);
582 }
583
584 while (trimmedLine.contains(StringPool.DOUBLE_SPACE) &&
585 !trimmedLine.contains(
586 StringPool.QUOTE + StringPool.DOUBLE_SPACE) &&
587 !fileName.endsWith(".vm")) {
588
589 line = StringUtil.replaceLast(
590 line, StringPool.DOUBLE_SPACE, StringPool.SPACE);
591
592 trimmedLine = StringUtil.replaceLast(
593 trimmedLine, StringPool.DOUBLE_SPACE, StringPool.SPACE);
594 }
595 }
596
597 if (!fileName.endsWith("/touch.jsp")) {
598 int x = line.indexOf("<%@ include file");
599
600 if (x != -1) {
601 x = line.indexOf(StringPool.QUOTE, x);
602
603 int y = line.indexOf(StringPool.QUOTE, x + 1);
604
605 if (y != -1) {
606 String includeFileName = line.substring(x + 1, y);
607
608 Matcher matcher = _jspIncludeFilePattern.matcher(
609 includeFileName);
610
611 if (!matcher.find()) {
612 processErrorMessage(
613 fileName,
614 "include: " + fileName + " " + lineCount);
615 }
616 }
617 }
618 }
619
620 line = replacePrimitiveWrapperInstantiation(
621 fileName, line, lineCount);
622
623 previousLine = line;
624
625 sb.append(line);
626 sb.append("\n");
627 }
628
629 unsyncBufferedReader.close();
630
631 content = sb.toString();
632
633 if (content.endsWith("\n")) {
634 content = content.substring(0, content.length() - 1);
635 }
636
637 content = formatTaglibQuotes(fileName, content, StringPool.QUOTE);
638 content = formatTaglibQuotes(fileName, content, StringPool.APOSTROPHE);
639
640 if (Validator.isNotNull(previousAttributeAndValue)) {
641 content = StringUtil.replaceFirst(
642 content,
643 previousAttributeAndValue + "\n" + currentAttributeAndValue,
644 currentAttributeAndValue + "\n" + previousAttributeAndValue);
645 }
646
647 if (hasUnsortedExceptions) {
648 if ((StringUtil.count(content, currentException) > 1) ||
649 (StringUtil.count(content, previousException) > 1)) {
650
651 processErrorMessage(
652 fileName, "unsorted exceptions: " + fileName);
653 }
654 else {
655 content = StringUtil.replaceFirst(
656 content, previousException, currentException);
657
658 content = StringUtil.replaceLast(
659 content, currentException, previousException);
660 }
661 }
662
663 return content;
664 }
665
666 protected String formatTaglibQuotes(
667 String fileName, String content, String quoteType) {
668
669 String quoteFix = StringPool.APOSTROPHE;
670
671 if (quoteFix.equals(quoteType)) {
672 quoteFix = StringPool.QUOTE;
673 }
674
675 Pattern pattern = Pattern.compile(getTaglibRegex(quoteType));
676
677 Matcher matcher = pattern.matcher(content);
678
679 while (matcher.find()) {
680 int x = content.indexOf(quoteType + "<%=", matcher.start());
681 int y = content.indexOf("%>" + quoteType, x);
682
683 while ((x != -1) && (y != -1)) {
684 String result = content.substring(x + 1, y + 2);
685
686 if (result.contains(quoteType)) {
687 int lineCount = 1;
688
689 char[] contentCharArray = content.toCharArray();
690
691 for (int i = 0; i < x; i++) {
692 if (contentCharArray[i] == CharPool.NEW_LINE) {
693 lineCount++;
694 }
695 }
696
697 if (!result.contains(quoteFix)) {
698 StringBundler sb = new StringBundler(5);
699
700 sb.append(content.substring(0, x));
701 sb.append(quoteFix);
702 sb.append(result);
703 sb.append(quoteFix);
704 sb.append(content.substring(y + 3, content.length()));
705
706 content = sb.toString();
707 }
708 else {
709 processErrorMessage(
710 fileName, "taglib: " + fileName + " " + lineCount);
711 }
712 }
713
714 x = content.indexOf(quoteType + "<%=", y);
715
716 if (x > matcher.end()) {
717 break;
718 }
719
720 y = content.indexOf("%>" + quoteType, x);
721 }
722 }
723
724 return content;
725 }
726
727 protected List<String> getJSPDuplicateImports(
728 String fileName, String content, List<String> importLines) {
729
730 List<String> duplicateImports = new ArrayList<String>();
731
732 for (String importLine : importLines) {
733 int x = content.indexOf("<%@ include file=");
734
735 if (x == -1) {
736 continue;
737 }
738
739 int y = content.indexOf("<%@ page import=");
740
741 if (y == -1) {
742 continue;
743 }
744
745 if ((x < y) && isJSPDuplicateImport(fileName, importLine, false)) {
746 duplicateImports.add(importLine);
747 }
748 }
749
750 return duplicateImports;
751 }
752
753 protected String getTaglibRegex(String quoteType) {
754 StringBuilder sb = new StringBuilder();
755
756 sb.append("<(");
757
758 for (int i = 0; i < _TAG_LIBRARIES.length; i++) {
759 sb.append(_TAG_LIBRARIES[i]);
760 sb.append(StringPool.PIPE);
761 }
762
763 sb.deleteCharAt(sb.length() - 1);
764 sb.append("):([^>]|%>)*");
765 sb.append(quoteType);
766 sb.append("<%=.*");
767 sb.append(quoteType);
768 sb.append(".*%>");
769 sb.append(quoteType);
770 sb.append("([^>]|%>)*>");
771
772 return sb.toString();
773 }
774
775 protected String getVariableName(String line) {
776 if (!line.endsWith(";") || line.startsWith("
777 return null;
778 }
779
780 String variableName = null;
781
782 int x = line.indexOf(" = ");
783
784 if (x == -1) {
785 int y = line.lastIndexOf(" ");
786
787 if (y != -1) {
788 variableName = line.substring(y + 1, line.length() - 1);
789 }
790 }
791 else {
792 line = line.substring(0, x);
793
794 int y = line.lastIndexOf(" ");
795
796 if (y != -1) {
797 variableName = line.substring(y + 1);
798 }
799 }
800
801 if (Validator.isVariableName(variableName)) {
802 return variableName;
803 }
804
805 return null;
806 }
807
808 protected boolean hasUnusedVariable(String fileName, String line) {
809 if (line.contains(": ")) {
810 return false;
811 }
812
813 String variableName = getVariableName(line);
814
815 if (Validator.isNull(variableName) || variableName.equals("false") ||
816 variableName.equals("true")) {
817
818 return false;
819 }
820
821 Set<String> includeFileNames = new HashSet<String>();
822
823 includeFileNames.add(fileName);
824
825 Set<String> checkedFileNames = new HashSet<String>();
826
827 return !isClassOrVariableRequired(
828 fileName, variableName, includeFileNames, checkedFileNames);
829 }
830
831 protected boolean isClassOrVariableRequired(
832 String fileName, String name, Set<String> includeFileNames,
833 Set<String> checkedFileNames) {
834
835 if (checkedFileNames.contains(fileName)) {
836 return false;
837 }
838
839 checkedFileNames.add(fileName);
840
841 String content = _jspContents.get(fileName);
842
843 if (Validator.isNull(content)) {
844 return false;
845 }
846
847 Pattern pattern = Pattern.compile(
848 "[^A-Za-z0-9_]" + name + "[^A-Za-z0-9_]");
849
850 Matcher matcher = pattern.matcher(content);
851
852 if (matcher.find() &&
853 ((checkedFileNames.size() > 1) || matcher.find())) {
854
855 return true;
856 }
857
858 addJSPIncludeFileNames(fileName, includeFileNames);
859
860 String docrootPath = fileName.substring(
861 0, fileName.indexOf("docroot") + 7);
862
863 fileName = fileName.replaceFirst(docrootPath, StringPool.BLANK);
864
865 if (fileName.endsWith("init.jsp") || fileName.endsWith("init.jspf") ||
866 fileName.contains("init-ext.jsp")) {
867
868 addJSPReferenceFileNames(fileName, includeFileNames);
869 }
870
871 String[] includeFileNamesArray = includeFileNames.toArray(
872 new String[includeFileNames.size()]);
873
874 for (String includeFileName : includeFileNamesArray) {
875 if (!checkedFileNames.contains(includeFileName) &&
876 isClassOrVariableRequired(
877 includeFileName, name, includeFileNames,
878 checkedFileNames)) {
879
880 return true;
881 }
882 }
883
884 return false;
885 }
886
887 protected boolean isJSPAttributName(String attributeName) {
888 if (Validator.isNull(attributeName)) {
889 return false;
890 }
891
892 Matcher matcher = _jspAttributeNamePattern.matcher(attributeName);
893
894 return matcher.matches();
895 }
896
897 protected boolean isJSPDuplicateImport(
898 String fileName, String importLine, boolean checkFile) {
899
900 String content = _jspContents.get(fileName);
901
902 if (Validator.isNull(content)) {
903 return false;
904 }
905
906 int x = importLine.indexOf("page");
907
908 if (x == -1) {
909 return false;
910 }
911
912 if (checkFile && content.contains(importLine.substring(x))) {
913 return true;
914 }
915
916 int y = content.indexOf("<%@ include file=");
917
918 if (y == -1) {
919 return false;
920 }
921
922 y = content.indexOf(StringPool.QUOTE, y);
923
924 if (y == -1) {
925 return false;
926 }
927
928 int z = content.indexOf(StringPool.QUOTE, y + 1);
929
930 if (z == -1) {
931 return false;
932 }
933
934 String includeFileName = content.substring(y + 1, z);
935
936 String docrootPath = fileName.substring(
937 0, fileName.indexOf("docroot") + 7);
938
939 includeFileName = docrootPath + includeFileName;
940
941 return isJSPDuplicateImport(includeFileName, importLine, true);
942 }
943
944 protected String sortJSPAttributes(
945 String fileName, String line, int lineCount) {
946
947 String s = line;
948
949 int x = s.indexOf(StringPool.SPACE);
950
951 if (x == -1) {
952 return line;
953 }
954
955 s = s.substring(x + 1);
956
957 String previousAttribute = null;
958 String previousAttributeAndValue = null;
959
960 boolean wrongOrder = false;
961
962 for (x = 0;;) {
963 x = s.indexOf(StringPool.EQUAL);
964
965 if ((x == -1) || (s.length() <= (x + 1))) {
966 return line;
967 }
968
969 String attribute = s.substring(0, x);
970
971 if (!isJSPAttributName(attribute)) {
972 return line;
973 }
974
975 if (Validator.isNotNull(previousAttribute) &&
976 (previousAttribute.compareTo(attribute) > 0)) {
977
978 wrongOrder = true;
979 }
980
981 s = s.substring(x + 1);
982
983 char delimeter = s.charAt(0);
984
985 if ((delimeter != CharPool.APOSTROPHE) &&
986 (delimeter != CharPool.QUOTE)) {
987
988 processErrorMessage(
989 fileName, "delimeter: " + fileName + " " + lineCount);
990
991 return line;
992 }
993
994 s = s.substring(1);
995
996 String value = null;
997
998 int y = -1;
999
1000 while (true) {
1001 y = s.indexOf(delimeter, y + 1);
1002
1003 if ((y == -1) || (s.length() <= (y + 1))) {
1004 return line;
1005 }
1006
1007 value = s.substring(0, y);
1008
1009 if (value.startsWith("<%")) {
1010 int endJavaCodeSignCount = StringUtil.count(value, "%>");
1011 int startJavaCodeSignCount = StringUtil.count(value, "<%");
1012
1013 if (endJavaCodeSignCount == startJavaCodeSignCount) {
1014 break;
1015 }
1016 }
1017 else {
1018 int greaterThanCount = StringUtil.count(
1019 value, StringPool.GREATER_THAN);
1020 int lessThanCount = StringUtil.count(
1021 value, StringPool.LESS_THAN);
1022
1023 if (greaterThanCount == lessThanCount) {
1024 break;
1025 }
1026 }
1027 }
1028
1029 if ((delimeter == CharPool.APOSTROPHE) &&
1030 !value.contains(StringPool.QUOTE)) {
1031
1032 return StringUtil.replace(
1033 line, StringPool.APOSTROPHE + value + StringPool.APOSTROPHE,
1034 StringPool.QUOTE + value + StringPool.QUOTE);
1035 }
1036
1037 StringBundler sb = new StringBundler(5);
1038
1039 sb.append(attribute);
1040 sb.append(StringPool.EQUAL);
1041 sb.append(delimeter);
1042 sb.append(value);
1043 sb.append(delimeter);
1044
1045 String currentAttributeAndValue = sb.toString();
1046
1047 if (wrongOrder) {
1048 if ((StringUtil.count(line, currentAttributeAndValue) == 1) &&
1049 (StringUtil.count(line, previousAttributeAndValue) == 1)) {
1050
1051 line = StringUtil.replaceFirst(
1052 line, previousAttributeAndValue,
1053 currentAttributeAndValue);
1054
1055 line = StringUtil.replaceLast(
1056 line, currentAttributeAndValue,
1057 previousAttributeAndValue);
1058 }
1059
1060 return line;
1061 }
1062
1063 s = s.substring(y + 1);
1064
1065 s = StringUtil.trimLeading(s);
1066
1067 previousAttribute = attribute;
1068 previousAttributeAndValue = currentAttributeAndValue;
1069 }
1070 }
1071
1072 protected String stripJSPImports(String fileName, String content)
1073 throws IOException {
1074
1075 fileName = fileName.replace(
1076 CharPool.BACK_SLASH, CharPool.FORWARD_SLASH);
1077
1078 if (!fileName.contains("docroot") ||
1079 fileName.endsWith("init-ext.jsp")) {
1080
1081 return content;
1082 }
1083
1084 Matcher matcher = _jspImportPattern.matcher(content);
1085
1086 if (!matcher.find()) {
1087 return content;
1088 }
1089
1090 String imports = matcher.group();
1091
1092 imports = StringUtil.replace(
1093 imports, new String[] {"%><%@\r\n", "%><%@\n"},
1094 new String[] {"%>\r\n<%@ ", "%>\n<%@ "});
1095
1096 if (!fileName.endsWith("html/common/init.jsp") &&
1097 !fileName.endsWith("html/portal/init.jsp")) {
1098
1099 List<String> importLines = new ArrayList<String>();
1100
1101 UnsyncBufferedReader unsyncBufferedReader =
1102 new UnsyncBufferedReader(new UnsyncStringReader(imports));
1103
1104 String line = null;
1105
1106 while ((line = unsyncBufferedReader.readLine()) != null) {
1107 if (line.contains("import=")) {
1108 importLines.add(line);
1109 }
1110 }
1111
1112 List<String> unneededImports = getJSPDuplicateImports(
1113 fileName, content, importLines);
1114
1115 addJSPUnusedImports(fileName, importLines, unneededImports);
1116
1117 for (String unneededImport : unneededImports) {
1118 imports = StringUtil.replace(
1119 imports, unneededImport, StringPool.BLANK);
1120 }
1121 }
1122
1123 imports = formatImports(imports, 17);
1124
1125 String beforeImports = content.substring(0, matcher.start());
1126
1127 if (Validator.isNull(imports)) {
1128 beforeImports = StringUtil.replaceLast(
1129 beforeImports, "\n", StringPool.BLANK);
1130 }
1131
1132 String afterImports = content.substring(matcher.end());
1133
1134 if (Validator.isNull(afterImports)) {
1135 imports = StringUtil.replaceLast(imports, "\n", StringPool.BLANK);
1136
1137 content = beforeImports + imports;
1138
1139 return content;
1140 }
1141
1142 content = beforeImports + imports + "\n" + afterImports;
1143
1144 return content;
1145 }
1146
1147 private static final String[] _TAG_LIBRARIES = new String[] {
1148 "aui", "c", "html", "jsp", "liferay-portlet", "liferay-security",
1149 "liferay-theme", "liferay-ui", "liferay-util", "portlet", "struts",
1150 "tiles"
1151 };
1152
1153 private Pattern _jspAttributeNamePattern = Pattern.compile(
1154 "[a-z]+[-_a-zA-Z0-9]*");
1155 private Map<String, String> _jspContents = new HashMap<String, String>();
1156 private Pattern _jspImportPattern = Pattern.compile(
1157 "(<.*\n*page.import=\".*>\n*)+", Pattern.MULTILINE);
1158 private Pattern _jspIncludeFilePattern = Pattern.compile("/.*[.]jsp[f]?");
1159 private boolean _stripJSPImports = true;
1160 private Pattern _taglibLanguageKeyPattern = Pattern.compile(
1161 "(?:confirmation|label|(?:M|m)essage|message key|names|title)=\"[^A-Z" +
1162 "<=%\\[\\s]+\"");
1163 private Pattern _xssPattern = Pattern.compile(
1164 "\\s+([^\\s]+)\\s*=\\s*(Bean)?ParamUtil\\.getString\\(");
1165
1166 }