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