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