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.ArrayUtil;
020 import com.liferay.portal.kernel.util.CharPool;
021 import com.liferay.portal.kernel.util.GetterUtil;
022 import com.liferay.portal.kernel.util.ListUtil;
023 import com.liferay.portal.kernel.util.ReflectionUtil;
024 import com.liferay.portal.kernel.util.ReleaseInfo;
025 import com.liferay.portal.kernel.util.StringBundler;
026 import com.liferay.portal.kernel.util.StringPool;
027 import com.liferay.portal.kernel.util.StringUtil;
028 import com.liferay.portal.kernel.util.TextFormatter;
029 import com.liferay.portal.kernel.util.Validator;
030 import com.liferay.portal.util.FileImpl;
031 import com.liferay.portal.xml.SAXReaderImpl;
032
033 import java.io.File;
034 import java.io.FileInputStream;
035 import java.io.FileNotFoundException;
036 import java.io.IOException;
037 import java.io.InputStream;
038
039 import java.util.ArrayList;
040 import java.util.Enumeration;
041 import java.util.HashMap;
042 import java.util.List;
043 import java.util.Map;
044 import java.util.Properties;
045 import java.util.regex.Matcher;
046 import java.util.regex.Pattern;
047
048 import org.apache.tools.ant.DirectoryScanner;
049
050
056 public abstract class BaseSourceProcessor implements SourceProcessor {
057
058 public BaseSourceProcessor() {
059 portalSource = _isPortalSource();
060
061 try {
062 _properties = _getProperties();
063 }
064 catch (Exception e) {
065 ReflectionUtil.throwException(e);
066 }
067 }
068
069 @Override
070 public void format(
071 boolean useProperties, boolean printErrors, boolean autoFix)
072 throws Exception {
073
074 _init(useProperties, printErrors, autoFix);
075
076 format();
077
078 sourceFormatterHelper.close();
079 }
080
081 @Override
082 public String format(
083 String fileName, boolean useProperties, boolean printErrors,
084 boolean autoFix)
085 throws Exception {
086
087 try {
088 _init(useProperties, printErrors, autoFix);
089
090 return format(fileName);
091 }
092 finally {
093 sourceFormatterHelper.close();
094 }
095 }
096
097 @Override
098 public List<String> getErrorMessages() {
099 List<String> errorMessages = new ArrayList<String>();
100
101 for (Map.Entry<String, List<String>> entry :
102 _errorMessagesMap.entrySet()) {
103
104 errorMessages.addAll(entry.getValue());
105 }
106
107 return errorMessages;
108 }
109
110 @Override
111 public SourceMismatchException getFirstSourceMismatchException() {
112 return _firstSourceMismatchException;
113 }
114
115 protected static boolean isExcluded(
116 List<String> exclusions, String absolutePath) {
117
118 return isExcluded(exclusions, absolutePath, -1);
119 }
120
121 protected static boolean isExcluded(
122 List<String> exclusions, String absolutePath, int lineCount) {
123
124 return isExcluded(exclusions, absolutePath, lineCount, null);
125 }
126
127 protected static boolean isExcluded(
128 List<String> exclusions, String absolutePath, int lineCount,
129 String javaTermName) {
130
131 if (ListUtil.isEmpty(exclusions)) {
132 return false;
133 }
134
135 String absolutePathWithJavaTermName = null;
136
137 if (Validator.isNotNull(javaTermName)) {
138 absolutePathWithJavaTermName =
139 absolutePath + StringPool.AT + javaTermName;
140 }
141
142 String absolutePathWithLineCount = null;
143
144 if (lineCount > 0) {
145 absolutePathWithLineCount =
146 absolutePath + StringPool.AT + lineCount;
147 }
148
149 for (String exclusion : exclusions) {
150 if (absolutePath.endsWith(exclusion) ||
151 ((absolutePathWithJavaTermName != null) &&
152 absolutePathWithJavaTermName.endsWith(exclusion)) ||
153 ((absolutePathWithLineCount != null) &&
154 absolutePathWithLineCount.endsWith(exclusion))) {
155
156 return true;
157 }
158 }
159
160 return false;
161 }
162
163 protected static void processErrorMessage(String fileName, String message) {
164 List<String> errorMessages = _errorMessagesMap.get(fileName);
165
166 if (errorMessages == null) {
167 errorMessages = new ArrayList<String>();
168 }
169
170 errorMessages.add(message);
171
172 _errorMessagesMap.put(fileName, errorMessages);
173 }
174
175 protected void checkEmptyCollection(
176 String line, String fileName, int lineCount) {
177
178
179
180 Matcher matcher = emptyCollectionPattern.matcher(line);
181
182 if (matcher.find()) {
183 String collectionType = TextFormatter.format(
184 matcher.group(1), TextFormatter.J);
185
186 processErrorMessage(
187 fileName,
188 "Use Collections.empty" + collectionType + "(): " + fileName +
189 " " + lineCount);
190 }
191 }
192
193 protected void checkIfClauseParentheses(
194 String ifClause, String fileName, int lineCount) {
195
196 int quoteCount = StringUtil.count(ifClause, StringPool.QUOTE);
197
198 if ((quoteCount % 2) == 1) {
199 return;
200 }
201
202 ifClause = stripQuotes(ifClause, CharPool.QUOTE);
203
204 ifClause = stripQuotes(ifClause, CharPool.APOSTROPHE);
205
206 if (ifClause.contains(StringPool.DOUBLE_SLASH) ||
207 ifClause.contains("")) {
208
209 return;
210 }
211
212 if (hasRedundantParentheses(ifClause, "||", "&&") ||
213 hasRedundantParentheses(ifClause, "&&", "||")) {
214
215 processErrorMessage(
216 fileName,
217 "redundant parentheses: " + fileName + " " + lineCount);
218 }
219
220 ifClause = stripRedundantParentheses(ifClause);
221
222 int level = 0;
223 int max = StringUtil.count(ifClause, StringPool.OPEN_PARENTHESIS);
224 int previousParenthesisPos = -1;
225
226 int[] levels = new int[max];
227
228 for (int i = 0; i < ifClause.length(); i++) {
229 char c = ifClause.charAt(i);
230
231 if ((c == CharPool.OPEN_PARENTHESIS) ||
232 (c == CharPool.CLOSE_PARENTHESIS)) {
233
234 if (previousParenthesisPos != -1) {
235 String s = ifClause.substring(
236 previousParenthesisPos + 1, i);
237
238 if (hasMissingParentheses(s)) {
239 processErrorMessage(
240 fileName,
241 "missing parentheses: " + fileName + " " +
242 lineCount);
243 }
244 }
245
246 previousParenthesisPos = i;
247
248 if (c == CharPool.OPEN_PARENTHESIS) {
249 levels[level] = i;
250
251 level += 1;
252 }
253 else {
254 int posOpenParenthesis = levels[level - 1];
255
256 if (level > 1) {
257 char nextChar = ifClause.charAt(i + 1);
258 char previousChar = ifClause.charAt(
259 posOpenParenthesis - 1);
260
261 if (!Character.isLetterOrDigit(nextChar) &&
262 (nextChar != CharPool.PERIOD) &&
263 !Character.isLetterOrDigit(previousChar)) {
264
265 String s = ifClause.substring(
266 posOpenParenthesis + 1, i);
267
268 if (hasRedundantParentheses(s)) {
269 processErrorMessage(
270 fileName,
271 "redundant parentheses: " + fileName + " " +
272 lineCount);
273 }
274 }
275
276 if ((previousChar == CharPool.OPEN_PARENTHESIS) &&
277 (nextChar == CharPool.CLOSE_PARENTHESIS)) {
278
279 processErrorMessage(
280 fileName,
281 "redundant parentheses: " + fileName + " " +
282 lineCount);
283 }
284 }
285
286 level -= 1;
287 }
288 }
289 }
290 }
291
292 protected void checkInefficientStringMethods(
293 String line, String fileName, String absolutePath, int lineCount) {
294
295 if (isRunsOutsidePortal(absolutePath) ||
296 fileName.endsWith("GetterUtil.java")) {
297
298 return;
299 }
300
301 String methodName = "toLowerCase";
302
303 int pos = line.indexOf(".toLowerCase()");
304
305 if (pos == -1) {
306 methodName = "toUpperCase";
307
308 pos = line.indexOf(".toUpperCase()");
309 }
310
311 if ((pos == -1) && !line.contains("StringUtil.equalsIgnoreCase(")) {
312 methodName = "equalsIgnoreCase";
313
314 pos = line.indexOf(".equalsIgnoreCase(");
315 }
316
317 if (pos != -1) {
318 processErrorMessage(
319 fileName,
320 "Use StringUtil." + methodName + ": " + fileName + " " +
321 lineCount);
322 }
323 }
324
325 protected void checkLanguageKeys(
326 String fileName, String content, Pattern pattern)
327 throws IOException {
328
329 String fileExtension = fileUtil.getExtension(fileName);
330
331 if (!portalSource || fileExtension.equals("vm")) {
332 return;
333 }
334
335 if (_portalLanguageProperties == null) {
336 _portalLanguageProperties = new Properties();
337
338 ClassLoader classLoader =
339 BaseSourceProcessor.class.getClassLoader();
340
341 InputStream inputStream = classLoader.getResourceAsStream(
342 "content/Language.properties");
343
344 _portalLanguageProperties.load(inputStream);
345 }
346
347 Matcher matcher = pattern.matcher(content);
348
349 while (matcher.find()) {
350 String[] languageKeys = getLanguageKeys(matcher);
351
352 for (String languageKey : languageKeys) {
353 if (Validator.isNumber(languageKey) ||
354 languageKey.endsWith(StringPool.DASH) ||
355 languageKey.endsWith(StringPool.OPEN_BRACKET) ||
356 languageKey.endsWith(StringPool.PERIOD) ||
357 languageKey.endsWith(StringPool.UNDERLINE) ||
358 languageKey.startsWith(StringPool.DASH) ||
359 languageKey.startsWith(StringPool.OPEN_BRACKET) ||
360 languageKey.startsWith(StringPool.OPEN_CURLY_BRACE) ||
361 languageKey.startsWith(StringPool.PERIOD) ||
362 languageKey.startsWith(StringPool.UNDERLINE) ||
363 _portalLanguageProperties.containsKey(languageKey)) {
364
365 continue;
366 }
367
368 Properties languageProperties = getLanguageProperties(fileName);
369
370 if ((languageProperties == null) ||
371 !languageProperties.containsKey(languageKey)) {
372
373 processErrorMessage(
374 fileName,
375 "missing language key: " + languageKey +
376 StringPool.SPACE + fileName);
377 }
378 }
379 }
380 }
381
382 protected void checkStringBundler(
383 String line, String fileName, int lineCount) {
384
385 if ((!line.startsWith("sb.append(") && !line.contains("SB.append(")) ||
386 !line.endsWith(");")) {
387
388 return;
389 }
390
391 int pos = line.indexOf(".append(");
392
393 line = line.substring(pos + 8, line.length() - 2);
394
395 line = stripQuotes(line, CharPool.QUOTE);
396
397 if (!line.contains(" + ")) {
398 return;
399 }
400
401 String[] lineParts = StringUtil.split(line, " + ");
402
403 for (String linePart : lineParts) {
404 int closeParenthesesCount = StringUtil.count(
405 linePart, StringPool.CLOSE_PARENTHESIS);
406 int openParenthesesCount = StringUtil.count(
407 linePart, StringPool.OPEN_PARENTHESIS);
408
409 if (closeParenthesesCount != openParenthesesCount) {
410 return;
411 }
412
413 if (Validator.isNumber(linePart)) {
414 return;
415 }
416 }
417
418 processErrorMessage(fileName, "plus: " + fileName + " " + lineCount);
419 }
420
421 protected abstract String doFormat(
422 File file, String fileName, String absolutePath, String content)
423 throws Exception;
424
425 protected String fixCompatClassImports(String absolutePath, String content)
426 throws IOException {
427
428 if (portalSource || !_usePortalCompatImport ||
429 absolutePath.contains("/ext-") ||
430 absolutePath.contains("/portal-compat-shared/")) {
431
432 return content;
433 }
434
435 Map<String, String> compatClassNamesMap = getCompatClassNamesMap();
436
437 String newContent = content;
438
439 for (Map.Entry<String, String> entry : compatClassNamesMap.entrySet()) {
440 String compatClassName = entry.getKey();
441 String extendedClassName = entry.getValue();
442
443 Pattern pattern = Pattern.compile(extendedClassName + "\\W");
444
445 while (true) {
446 Matcher matcher = pattern.matcher(newContent);
447
448 if (!matcher.find()) {
449 break;
450 }
451
452 newContent =
453 newContent.substring(0, matcher.start()) + compatClassName +
454 newContent.substring(matcher.end() - 1);
455 }
456 }
457
458 return newContent;
459 }
460
461 protected String fixCopyright(
462 String content, String absolutePath, String fileName)
463 throws IOException {
464
465 if (_copyright == null) {
466 _copyright = getContent("copyright.txt", 4);
467 }
468
469 String copyright = _copyright;
470
471 if (fileName.endsWith(".vm") || Validator.isNull(copyright)) {
472 return content;
473 }
474
475 if (_oldCopyright == null) {
476 _oldCopyright = getContent("old-copyright.txt", 4);
477 }
478
479 if (Validator.isNotNull(_oldCopyright) &&
480 content.contains(_oldCopyright)) {
481
482 content = StringUtil.replace(content, _oldCopyright, copyright);
483
484 processErrorMessage(fileName, "old (c): " + fileName);
485 }
486
487 if (!content.contains(copyright)) {
488 String customCopyright = getCustomCopyright(absolutePath);
489
490 if (Validator.isNotNull(customCopyright)) {
491 copyright = customCopyright;
492 }
493
494 if (!content.contains(copyright)) {
495 processErrorMessage(fileName, "(c): " + fileName);
496 }
497 }
498
499 if (fileName.endsWith(".jsp") || fileName.endsWith(".jspf")) {
500 content = StringUtil.replace(
501 content, "<%\n" + copyright + "\n%>",
502 "<%--\n" + copyright + "\n--%>");
503 }
504
505 int x = content.indexOf("* Copyright (c) 2000-");
506
507 if (x == -1) {
508 return content;
509 }
510
511 int y = content.indexOf("Liferay", x);
512
513 String contentCopyrightYear = content.substring(x, y);
514
515 x = copyright.indexOf("* Copyright (c) 2000-");
516
517 if (x == -1) {
518 return content;
519 }
520
521 y = copyright.indexOf("Liferay", x);
522
523 String copyrightYear = copyright.substring(x, y);
524
525 return StringUtil.replace(content, contentCopyrightYear, copyrightYear);
526 }
527
528 protected String fixIncorrectParameterTypeForLanguageUtil(
529 String content, boolean autoFix, String fileName) {
530
531 if (portalSource) {
532 return content;
533 }
534
535 String expectedParameter = getProperty(
536 "languageutil.expected.parameter");
537 String incorrectParameter = getProperty(
538 "languageutil.incorrect.parameter");
539
540 if (!content.contains(
541 "LanguageUtil.format(" + incorrectParameter + ", ") &&
542 !content.contains(
543 "LanguageUtil.get(" + incorrectParameter + ", ")) {
544
545 return content;
546 }
547
548 if (autoFix) {
549 content = StringUtil.replace(
550 content,
551 new String[] {
552 "LanguageUtil.format(" + incorrectParameter + ", ",
553 "LanguageUtil.get(" + incorrectParameter + ", "
554 },
555 new String[] {
556 "LanguageUtil.format(" + expectedParameter + ", ",
557 "LanguageUtil.get(" + expectedParameter + ", "
558 });
559 }
560 else {
561 processErrorMessage(
562 fileName,
563 "(Unicode)LanguageUtil.format/get methods require " +
564 expectedParameter + " parameter instead of " +
565 incorrectParameter + " " + fileName);
566 }
567
568 return content;
569 }
570
571 protected String fixSessionKey(
572 String fileName, String content, Pattern pattern) {
573
574 Matcher matcher = pattern.matcher(content);
575
576 if (!matcher.find()) {
577 return content;
578 }
579
580 String newContent = content;
581
582 do {
583 String match = matcher.group();
584
585 String s = null;
586
587 if (pattern.equals(sessionKeyPattern)) {
588 s = StringPool.COMMA;
589 }
590 else if (pattern.equals(taglibSessionKeyPattern)) {
591 s = "key=";
592 }
593
594 int x = match.indexOf(s);
595
596 if (x == -1) {
597 continue;
598 }
599
600 x = x + s.length();
601
602 String substring = match.substring(x).trim();
603
604 String quote = StringPool.BLANK;
605
606 if (substring.startsWith(StringPool.APOSTROPHE)) {
607 quote = StringPool.APOSTROPHE;
608 }
609 else if (substring.startsWith(StringPool.QUOTE)) {
610 quote = StringPool.QUOTE;
611 }
612 else {
613 continue;
614 }
615
616 int y = match.indexOf(quote, x);
617 int z = match.indexOf(quote, y + 1);
618
619 if ((y == -1) || (z == -1)) {
620 continue;
621 }
622
623 String prefix = match.substring(0, y + 1);
624 String suffix = match.substring(z);
625 String oldKey = match.substring(y + 1, z);
626
627 boolean alphaNumericKey = true;
628
629 for (char c : oldKey.toCharArray()) {
630 if (!Validator.isChar(c) && !Validator.isDigit(c) &&
631 (c != CharPool.DASH) && (c != CharPool.UNDERLINE)) {
632
633 alphaNumericKey = false;
634 }
635 }
636
637 if (!alphaNumericKey) {
638 continue;
639 }
640
641 String newKey = TextFormatter.format(oldKey, TextFormatter.O);
642
643 newKey = TextFormatter.format(newKey, TextFormatter.M);
644
645 if (newKey.equals(oldKey)) {
646 continue;
647 }
648
649 String oldSub = prefix.concat(oldKey).concat(suffix);
650 String newSub = prefix.concat(newKey).concat(suffix);
651
652 newContent = StringUtil.replaceFirst(newContent, oldSub, newSub);
653 }
654 while (matcher.find());
655
656 return newContent;
657 }
658
659 protected abstract void format() throws Exception;
660
661 protected String format(
662 File file, String fileName, String absolutePath, String content)
663 throws Exception {
664
665 _errorMessagesMap.remove(fileName);
666
667 String newContent = doFormat(file, fileName, absolutePath, content);
668
669 newContent = StringUtil.replace(
670 newContent, StringPool.RETURN, StringPool.BLANK);
671
672 if (content.equals(newContent)) {
673 return content;
674 }
675
676 return format(file, fileName, absolutePath, newContent);
677 }
678
679 protected String format(String fileName) throws Exception {
680 File file = new File(BASEDIR + fileName);
681
682 fileName = StringUtil.replace(
683 fileName, StringPool.BACK_SLASH, StringPool.SLASH);
684
685 String absolutePath = getAbsolutePath(file);
686
687 String content = fileUtil.read(file);
688
689 String newContent = format(file, fileName, absolutePath, content);
690
691 processFormattedFile(file, fileName, content, newContent);
692
693 return newContent;
694 }
695
696 protected String formatJavaTerms(
697 String fileName, String absolutePath, String content,
698 String javaClassContent, int javaClassLineCount,
699 List<String> javaTermAccessLevelModifierExclusions,
700 List<String> javaTermSortExclusions,
701 List<String> testAnnotationsExclusions)
702 throws Exception {
703
704 JavaClass javaClass = new JavaClass(
705 fileName, absolutePath, javaClassContent, javaClassLineCount,
706 StringPool.TAB);
707
708 String newJavaClassContent = javaClass.formatJavaTerms(
709 javaTermAccessLevelModifierExclusions, javaTermSortExclusions,
710 testAnnotationsExclusions);
711
712 if (!javaClassContent.equals(newJavaClassContent)) {
713 return StringUtil.replaceFirst(
714 content, javaClassContent, newJavaClassContent);
715 }
716
717 return content;
718 }
719
720 protected String getAbsolutePath(File file) {
721 String absolutePath = fileUtil.getAbsolutePath(file);
722
723 return StringUtil.replace(absolutePath, "/./", StringPool.SLASH);
724 }
725
726 protected Map<String, String> getCompatClassNamesMap() throws IOException {
727 if (_compatClassNamesMap != null) {
728 return _compatClassNamesMap;
729 }
730
731 Map<String, String> compatClassNamesMap = new HashMap<String, String>();
732
733 String[] includes = new String[] {
734 "**\\portal-compat-shared\\src\\com\\liferay\\compat\\**\\*.java"
735 };
736
737 String basedir = BASEDIR;
738
739 List<String> fileNames = new ArrayList<String>();
740
741 for (int i = 0; i < 3; i++) {
742 fileNames = getFileNames(basedir, new String[0], includes);
743
744 if (!fileNames.isEmpty()) {
745 break;
746 }
747
748 basedir = "../" + basedir;
749 }
750
751 for (String fileName : fileNames) {
752 if (!fileName.startsWith("shared")) {
753 break;
754 }
755
756 File file = new File(basedir + fileName);
757
758 String content = fileUtil.read(file);
759
760 fileName = StringUtil.replace(
761 fileName, StringPool.BACK_SLASH, StringPool.SLASH);
762
763 fileName = StringUtil.replace(
764 fileName, StringPool.SLASH, StringPool.PERIOD);
765
766 int pos = fileName.indexOf("com.");
767
768 String compatClassName = fileName.substring(pos);
769
770 compatClassName = compatClassName.substring(
771 0, compatClassName.length() - 5);
772
773 String extendedClassName = StringUtil.replace(
774 compatClassName, "compat.", StringPool.BLANK);
775
776 if (content.contains("extends " + extendedClassName)) {
777 compatClassNamesMap.put(compatClassName, extendedClassName);
778 }
779 }
780
781 _compatClassNamesMap = compatClassNamesMap;
782
783 return _compatClassNamesMap;
784 }
785
786 protected String getContent(String fileName, int level) throws IOException {
787 File file = getFile(fileName, level);
788
789 if (file != null) {
790 String content = fileUtil.read(file);
791
792 if (Validator.isNotNull(content)) {
793 return content;
794 }
795 }
796
797 return StringPool.BLANK;
798 }
799
800 protected String getCustomCopyright(String absolutePath)
801 throws IOException {
802
803 for (int x = absolutePath.length();;) {
804 x = absolutePath.lastIndexOf(StringPool.SLASH, x);
805
806 if (x == -1) {
807 break;
808 }
809
810 String copyright = fileUtil.read(
811 absolutePath.substring(0, x + 1) + "copyright.txt");
812
813 if (Validator.isNotNull(copyright)) {
814 return copyright;
815 }
816
817 x = x - 1;
818 }
819
820 return null;
821 }
822
823 protected File getFile(String fileName, int level) {
824 for (int i = 0; i < level; i++) {
825 if (fileUtil.exists(fileName)) {
826 return new File(fileName);
827 }
828
829 fileName = "../" + fileName;
830 }
831
832 return null;
833 }
834
835 protected List<String> getFileNames(
836 String basedir, String[] excludes, String[] includes) {
837
838 DirectoryScanner directoryScanner = new DirectoryScanner();
839
840 directoryScanner.setBasedir(basedir);
841
842 if (_excludes != null) {
843 excludes = ArrayUtil.append(excludes, _excludes);
844 }
845
846 directoryScanner.setExcludes(excludes);
847
848 directoryScanner.setIncludes(includes);
849
850 return sourceFormatterHelper.scanForFiles(directoryScanner);
851 }
852
853 protected List<String> getFileNames(String[] excludes, String[] includes) {
854 return getFileNames(BASEDIR, excludes, includes);
855 }
856
857 protected String[] getLanguageKeys(Matcher matcher) {
858 int groupCount = matcher.groupCount();
859
860 if (groupCount == 1) {
861 String languageKey = matcher.group(1);
862
863 if (Validator.isNotNull(languageKey)) {
864 return new String[] {languageKey};
865 }
866 }
867 else if (groupCount == 2) {
868 String languageKey = matcher.group(2);
869
870 languageKey = TextFormatter.format(languageKey, TextFormatter.P);
871
872 return new String[] {languageKey};
873 }
874
875 StringBundler sb = new StringBundler();
876
877 String match = matcher.group();
878
879 int count = 0;
880
881 for (int i = 0; i < match.length(); i++) {
882 char c = match.charAt(i);
883
884 switch (c) {
885 case CharPool.CLOSE_PARENTHESIS:
886 if (count <= 1) {
887 return new String[0];
888 }
889
890 count--;
891
892 break;
893
894 case CharPool.OPEN_PARENTHESIS:
895 count++;
896
897 break;
898
899 case CharPool.QUOTE:
900 if (count > 1) {
901 break;
902 }
903
904 while (i < match.length()) {
905 i++;
906
907 if (match.charAt(i) == CharPool.QUOTE) {
908 String languageKey = sb.toString();
909
910 if (match.startsWith("names")) {
911 return StringUtil.split(languageKey);
912 }
913 else {
914 return new String[] {languageKey};
915 }
916 }
917
918 sb.append(match.charAt(i));
919 }
920 }
921 }
922
923 return new String[0];
924 }
925
926 protected Properties getLanguageProperties(String fileName) {
927 StringBundler sb = new StringBundler(4);
928
929 int pos = fileName.indexOf("/docroot/");
930
931 sb.append(BASEDIR);
932
933 if (pos != -1) {
934 sb.append(fileName.substring(0, pos + 9));
935 sb.append("WEB-INF/src/");
936 }
937 else {
938 pos = fileName.indexOf("/src/");
939
940 if (pos == -1) {
941 return null;
942 }
943
944 sb.append(fileName.substring(0, pos + 5));
945 }
946
947 sb.append("content/Language.properties");
948
949 try {
950 Properties properties = new Properties();
951
952 InputStream inputStream = new FileInputStream(sb.toString());
953
954 properties.load(inputStream);
955
956 return properties;
957 }
958 catch (Exception e) {
959 }
960
961 return null;
962 }
963
964 protected String getMainReleaseVersion() {
965 if (_mainReleaseVersion != null) {
966 return _mainReleaseVersion;
967 }
968
969 String releaseVersion = ReleaseInfo.getVersion();
970
971 int pos = releaseVersion.lastIndexOf(StringPool.PERIOD);
972
973 _mainReleaseVersion = releaseVersion.substring(0, pos) + ".0";
974
975 return _mainReleaseVersion;
976 }
977
978 protected String getProperty(String key) {
979 return _properties.getProperty(key);
980 }
981
982 protected List<String> getPropertyList(String key) {
983 return ListUtil.fromString(
984 GetterUtil.getString(getProperty(key)), StringPool.COMMA);
985 }
986
987 protected boolean hasMissingParentheses(String s) {
988 if (Validator.isNull(s)) {
989 return false;
990 }
991
992 boolean containsAndOperator = s.contains("&&");
993 boolean containsOrOperator = s.contains("||");
994
995 if (containsAndOperator && containsOrOperator) {
996 return true;
997 }
998
999 boolean containsCompareOperator =
1000 (s.contains(" == ") || s.contains(" != ") || s.contains(" < ") ||
1001 s.contains(" > ") || s.contains(" =< ") || s.contains(" => ") ||
1002 s.contains(" <= ") || s.contains(" >= "));
1003 boolean containsMathOperator =
1004 (s.contains(" = ") || s.contains(" - ") || s.contains(" + ") ||
1005 s.contains(" & ") || s.contains(" % ") || s.contains(" * ") ||
1006 s.contains(" / "));
1007
1008 if (containsCompareOperator &&
1009 (containsAndOperator || containsOrOperator ||
1010 (containsMathOperator && !s.contains(StringPool.OPEN_BRACKET)))) {
1011
1012 return true;
1013 }
1014
1015 return false;
1016 }
1017
1018 protected boolean hasRedundantParentheses(String s) {
1019 if (!s.contains("&&") && !s.contains("||")) {
1020 for (int x = 0;;) {
1021 x = s.indexOf(StringPool.CLOSE_PARENTHESIS);
1022
1023 if (x == -1) {
1024 break;
1025 }
1026
1027 int y = s.substring(0, x).lastIndexOf(
1028 StringPool.OPEN_PARENTHESIS);
1029
1030 if (y == -1) {
1031 break;
1032 }
1033
1034 s = s.substring(0, y) + s.substring(x + 1);
1035 }
1036 }
1037
1038 if (Validator.isNotNull(s) && !s.contains(StringPool.SPACE)) {
1039 return true;
1040 }
1041 else {
1042 return false;
1043 }
1044 }
1045
1046 protected boolean hasRedundantParentheses(
1047 String s, String operator1, String operator2) {
1048
1049 String[] parts = StringUtil.split(s, operator1);
1050
1051 if (parts.length < 3) {
1052 return false;
1053 }
1054
1055 for (int i = 1; i < (parts.length - 1); i++) {
1056 String part = parts[i];
1057
1058 if (part.contains(operator2) || part.contains("!(")) {
1059 continue;
1060 }
1061
1062 int closeParenthesesCount = StringUtil.count(
1063 part, StringPool.CLOSE_PARENTHESIS);
1064 int openParenthesesCount = StringUtil.count(
1065 part, StringPool.OPEN_PARENTHESIS);
1066
1067 if (Math.abs(closeParenthesesCount - openParenthesesCount) == 1) {
1068 return true;
1069 }
1070 }
1071
1072 return false;
1073 }
1074
1075 protected boolean isAttributName(String attributeName) {
1076 if (Validator.isNull(attributeName)) {
1077 return false;
1078 }
1079
1080 Matcher matcher = attributeNamePattern.matcher(attributeName);
1081
1082 return matcher.matches();
1083 }
1084
1085 protected boolean isRunsOutsidePortal(String absolutePath) {
1086 if (_runOutsidePortalExclusions == null) {
1087 _runOutsidePortalExclusions = getPropertyList(
1088 "run.outside.portal.excludes");
1089 }
1090
1091 for (String runOutsidePortalExclusions : _runOutsidePortalExclusions) {
1092 if (absolutePath.contains(runOutsidePortalExclusions)) {
1093 return true;
1094 }
1095 }
1096
1097 return false;
1098 }
1099
1100 protected void processFormattedFile(
1101 File file, String fileName, String content, String newContent)
1102 throws IOException {
1103
1104 if (_printErrors) {
1105 List<String> errorMessages = _errorMessagesMap.get(fileName);
1106
1107 if (errorMessages != null) {
1108 for (String errorMessage : errorMessages) {
1109 sourceFormatterHelper.printError(fileName, errorMessage);
1110 }
1111 }
1112 }
1113
1114 if (content.equals(newContent)) {
1115 return;
1116 }
1117
1118 if (_autoFix) {
1119 fileUtil.write(file, newContent);
1120 }
1121 else if (_firstSourceMismatchException == null) {
1122 _firstSourceMismatchException = new SourceMismatchException(
1123 fileName, content, newContent);
1124 }
1125
1126 if (_printErrors) {
1127 sourceFormatterHelper.printError(fileName, file);
1128 }
1129 }
1130
1131 protected String replacePrimitiveWrapperInstantiation(
1132 String fileName, String line, int lineCount) {
1133
1134 if (true) {
1135 return line;
1136 }
1137
1138 String newLine = StringUtil.replace(
1139 line,
1140 new String[] {
1141 "new Boolean(", "new Byte(", "new Character(", "new Integer(",
1142 "new Long(", "new Short("
1143 },
1144 new String[] {
1145 "Boolean.valueOf(", "Byte.valueOf(", "Character.valueOf(",
1146 "Integer.valueOf(", "Long.valueOf(", "Short.valueOf("
1147 });
1148
1149 if (!line.equals(newLine)) {
1150 processErrorMessage(
1151 fileName, "> new Primitive(: " + fileName + " " + lineCount);
1152 }
1153
1154 return newLine;
1155 }
1156
1157 protected String sortAttributes(
1158 String fileName, String line, int lineCount,
1159 boolean allowApostropheDelimeter) {
1160
1161 String s = line;
1162
1163 int x = s.indexOf(StringPool.SPACE);
1164
1165 if (x == -1) {
1166 return line;
1167 }
1168
1169 s = s.substring(x + 1);
1170
1171 String previousAttribute = null;
1172 String previousAttributeAndValue = null;
1173
1174 boolean wrongOrder = false;
1175
1176 for (x = 0;;) {
1177 x = s.indexOf(StringPool.EQUAL);
1178
1179 if ((x == -1) || (s.length() <= (x + 1))) {
1180 return line;
1181 }
1182
1183 String attribute = s.substring(0, x);
1184
1185 if (!isAttributName(attribute)) {
1186 return line;
1187 }
1188
1189 if (Validator.isNotNull(previousAttribute) &&
1190 (previousAttribute.compareTo(attribute) > 0)) {
1191
1192 wrongOrder = true;
1193 }
1194
1195 s = s.substring(x + 1);
1196
1197 char delimeter = s.charAt(0);
1198
1199 if ((delimeter != CharPool.APOSTROPHE) &&
1200 (delimeter != CharPool.QUOTE)) {
1201
1202 if (delimeter != CharPool.AMPERSAND) {
1203 processErrorMessage(
1204 fileName, "delimeter: " + fileName + " " + lineCount);
1205 }
1206
1207 return line;
1208 }
1209
1210 s = s.substring(1);
1211
1212 String value = null;
1213
1214 int y = -1;
1215
1216 while (true) {
1217 y = s.indexOf(delimeter, y + 1);
1218
1219 if ((y == -1) || (s.length() <= (y + 1))) {
1220 return line;
1221 }
1222
1223 value = s.substring(0, y);
1224
1225 if (value.startsWith("<%")) {
1226 int endJavaCodeSignCount = StringUtil.count(value, "%>");
1227 int startJavaCodeSignCount = StringUtil.count(value, "<%");
1228
1229 if (endJavaCodeSignCount == startJavaCodeSignCount) {
1230 break;
1231 }
1232 }
1233 else {
1234 int greaterThanCount = StringUtil.count(
1235 value, StringPool.GREATER_THAN);
1236 int lessThanCount = StringUtil.count(
1237 value, StringPool.LESS_THAN);
1238
1239 if (greaterThanCount == lessThanCount) {
1240 break;
1241 }
1242 }
1243 }
1244
1245 if (delimeter == CharPool.APOSTROPHE) {
1246 if (!value.contains(StringPool.QUOTE)) {
1247 line = StringUtil.replace(
1248 line,
1249 StringPool.APOSTROPHE + value + StringPool.APOSTROPHE,
1250 StringPool.QUOTE + value + StringPool.QUOTE);
1251
1252 return sortAttributes(
1253 fileName, line, lineCount, allowApostropheDelimeter);
1254 }
1255 else if (!allowApostropheDelimeter) {
1256 String newValue = StringUtil.replace(
1257 value, StringPool.QUOTE, """);
1258
1259 line = StringUtil.replace(
1260 line,
1261 StringPool.APOSTROPHE + value + StringPool.APOSTROPHE,
1262 StringPool.QUOTE + newValue + StringPool.QUOTE);
1263
1264 return sortAttributes(
1265 fileName, line, lineCount, allowApostropheDelimeter);
1266 }
1267 }
1268
1269 StringBundler sb = new StringBundler(5);
1270
1271 sb.append(attribute);
1272 sb.append(StringPool.EQUAL);
1273 sb.append(delimeter);
1274 sb.append(value);
1275 sb.append(delimeter);
1276
1277 String currentAttributeAndValue = sb.toString();
1278
1279 if (wrongOrder) {
1280 if ((StringUtil.count(line, currentAttributeAndValue) == 1) &&
1281 (StringUtil.count(line, previousAttributeAndValue) == 1)) {
1282
1283 line = StringUtil.replaceFirst(
1284 line, previousAttributeAndValue,
1285 currentAttributeAndValue);
1286
1287 line = StringUtil.replaceLast(
1288 line, currentAttributeAndValue,
1289 previousAttributeAndValue);
1290
1291 return sortAttributes(
1292 fileName, line, lineCount, allowApostropheDelimeter);
1293 }
1294
1295 return line;
1296 }
1297
1298 s = s.substring(y + 1);
1299
1300 if (s.startsWith(StringPool.GREATER_THAN)) {
1301 x = s.indexOf(StringPool.SPACE);
1302
1303 if (x == -1) {
1304 return line;
1305 }
1306
1307 s = s.substring(x + 1);
1308
1309 previousAttribute = null;
1310 previousAttributeAndValue = null;
1311 }
1312 else {
1313 s = StringUtil.trimLeading(s);
1314
1315 previousAttribute = attribute;
1316 previousAttributeAndValue = currentAttributeAndValue;
1317 }
1318 }
1319 }
1320
1321 protected String stripLine(
1322 String s, char startDelimeter, char endDelimeter) {
1323
1324 boolean insideDelimeters = false;
1325 int level = 0;
1326
1327 StringBundler sb = new StringBundler();
1328
1329 for (int i = 0; i < s.length(); i++) {
1330 char c = s.charAt(i);
1331
1332 if (insideDelimeters) {
1333 if (c == endDelimeter) {
1334 if (level > 0) {
1335 level -= 1;
1336 }
1337 else {
1338 if ((c > 1) &&
1339 (s.charAt(i - 1) == CharPool.BACK_SLASH) &&
1340 (s.charAt(i - 2) != CharPool.BACK_SLASH)) {
1341
1342 continue;
1343 }
1344
1345 insideDelimeters = false;
1346 }
1347 }
1348 else if (c == startDelimeter) {
1349 level += 1;
1350 }
1351 }
1352 else if (c == startDelimeter) {
1353 insideDelimeters = true;
1354 }
1355 else {
1356 sb.append(c);
1357 }
1358 }
1359
1360 return sb.toString();
1361 }
1362
1363 protected String stripQuotes(String s, char delimeter) {
1364 return stripLine(s, delimeter, delimeter);
1365 }
1366
1367 protected String stripRedundantParentheses(String s) {
1368 for (int x = 0;;) {
1369 x = s.indexOf(StringPool.OPEN_PARENTHESIS, x + 1);
1370 int y = s.indexOf(StringPool.CLOSE_PARENTHESIS, x);
1371
1372 if ((x == -1) || (y == -1)) {
1373 return s;
1374 }
1375
1376 String linePart = s.substring(x + 1, y);
1377
1378 linePart = StringUtil.replace(
1379 linePart, StringPool.COMMA, StringPool.BLANK);
1380
1381 if (Validator.isAlphanumericName(linePart) ||
1382 Validator.isNull(linePart)) {
1383
1384 s = s.substring(0, x) + s.substring(y + 1);
1385 }
1386 }
1387 }
1388
1389 protected String trimContent(String content, boolean allowLeadingSpaces)
1390 throws IOException {
1391
1392 StringBundler sb = new StringBundler();
1393
1394 try (UnsyncBufferedReader unsyncBufferedReader =
1395 new UnsyncBufferedReader(new UnsyncStringReader(content))) {
1396
1397 String line = null;
1398
1399 while ((line = unsyncBufferedReader.readLine()) != null) {
1400 sb.append(trimLine(line, allowLeadingSpaces));
1401 sb.append("\n");
1402 }
1403 }
1404
1405 content = sb.toString();
1406
1407 if (content.endsWith("\n")) {
1408 content = content.substring(0, content.length() - 1);
1409 }
1410
1411 return content;
1412 }
1413
1414 protected String trimLine(String line, boolean allowLeadingSpaces) {
1415 if (line.trim().length() == 0) {
1416 return StringPool.BLANK;
1417 }
1418
1419 line = StringUtil.trimTrailing(line);
1420
1421 if (allowLeadingSpaces || !line.startsWith(StringPool.SPACE) ||
1422 line.startsWith(" *")) {
1423
1424 return line;
1425 }
1426
1427 if (!line.startsWith(StringPool.FOUR_SPACES)) {
1428 while (line.startsWith(StringPool.SPACE)) {
1429 line = StringUtil.replaceFirst(
1430 line, StringPool.SPACE, StringPool.BLANK);
1431 }
1432 }
1433 else {
1434 int pos = 0;
1435
1436 String temp = line;
1437
1438 while (temp.startsWith(StringPool.FOUR_SPACES)) {
1439 line = StringUtil.replaceFirst(
1440 line, StringPool.FOUR_SPACES, StringPool.TAB);
1441
1442 pos++;
1443
1444 temp = line.substring(pos);
1445 }
1446 }
1447
1448 return line;
1449 }
1450
1451 protected static final String BASEDIR = "./";
1452
1453 protected static Pattern attributeNamePattern = Pattern.compile(
1454 "[a-z]+[-_a-zA-Z0-9]*");
1455 protected static Pattern emptyCollectionPattern = Pattern.compile(
1456 "Collections\\.EMPTY_(LIST|MAP|SET)");
1457 protected static FileImpl fileUtil = FileImpl.getInstance();
1458 protected static Pattern languageKeyPattern = Pattern.compile(
1459 "LanguageUtil.(?:get|format)\\([^;%]+|Liferay.Language.get\\('([^']+)");
1460 protected static boolean portalSource;
1461 protected static SAXReaderImpl saxReaderUtil = SAXReaderImpl.getInstance();
1462 protected static Pattern sessionKeyPattern = Pattern.compile(
1463 "SessionErrors.(?:add|contains|get)\\([^;%&|!]+|".concat(
1464 "SessionMessages.(?:add|contains|get)\\([^;%&|!]+"),
1465 Pattern.MULTILINE);
1466 protected static SourceFormatterHelper sourceFormatterHelper;
1467 protected static Pattern taglibSessionKeyPattern = Pattern.compile(
1468 "<liferay-ui:error [^>]+>|<liferay-ui:success [^>]+>",
1469 Pattern.MULTILINE);
1470
1471 private String[] _getExcludes() {
1472 List<String> excludesList = ListUtil.fromString(
1473 GetterUtil.getString(
1474 System.getProperty("source.formatter.excludes")));
1475
1476 excludesList.addAll(getPropertyList("source.formatter.excludes"));
1477
1478 String[] includes = new String[] {"**\\source_formatter.ignore"};
1479
1480 List<String> ignoreFileNames = getFileNames(new String[0], includes);
1481
1482 for (String ignoreFileName : ignoreFileNames) {
1483 excludesList.add(
1484 ignoreFileName.substring(0, ignoreFileName.length() - 23) +
1485 "**");
1486 }
1487
1488 return excludesList.toArray(new String[excludesList.size()]);
1489 }
1490
1491 private Properties _getProperties() throws Exception {
1492 String fileName = "source-formatter.properties";
1493
1494 Properties properties = new Properties();
1495
1496 List<Properties> propertiesList = new ArrayList<Properties>();
1497
1498 int level = 2;
1499
1500 if (portalSource) {
1501 level = 3;
1502 }
1503
1504 for (int i = 0; i <= level; i++) {
1505 try {
1506 InputStream inputStream = new FileInputStream(fileName);
1507
1508 Properties props = new Properties();
1509
1510 props.load(inputStream);
1511
1512 propertiesList.add(props);
1513 }
1514 catch (FileNotFoundException fnfe) {
1515 }
1516
1517 fileName = "../" + fileName;
1518 }
1519
1520 if (propertiesList.isEmpty()) {
1521 return properties;
1522 }
1523
1524 properties = propertiesList.get(0);
1525
1526 if (propertiesList.size() == 1) {
1527 return properties;
1528 }
1529
1530 for (int i = 1; i < propertiesList.size(); i++) {
1531 Properties props = propertiesList.get(i);
1532
1533 Enumeration<String> enu =
1534 (Enumeration<String>)props.propertyNames();
1535
1536 while (enu.hasMoreElements()) {
1537 String key = enu.nextElement();
1538
1539 String value = props.getProperty(key);
1540
1541 if (Validator.isNull(value)) {
1542 continue;
1543 }
1544
1545 if (key.contains("excludes")) {
1546 String existingValue = properties.getProperty(key);
1547
1548 if (Validator.isNotNull(existingValue)) {
1549 value = existingValue + StringPool.COMMA + value;
1550 }
1551
1552 properties.put(key, value);
1553 }
1554 else if (!properties.containsKey(key)) {
1555 properties.put(key, value);
1556 }
1557 }
1558 }
1559
1560 return properties;
1561 }
1562
1563 private void _init(
1564 boolean useProperties, boolean printErrors, boolean autoFix)
1565 throws Exception {
1566
1567 _errorMessagesMap = new HashMap<String, List<String>>();
1568
1569 sourceFormatterHelper = new SourceFormatterHelper(useProperties);
1570
1571 sourceFormatterHelper.init();
1572
1573 _autoFix = autoFix;
1574
1575 _excludes = _getExcludes();
1576
1577 _printErrors = printErrors;
1578
1579 _usePortalCompatImport = GetterUtil.getBoolean(
1580 getProperty("use.portal.compat.import"));
1581 }
1582
1583 private boolean _isPortalSource() {
1584 if (getFile("portal-impl", 4) != null) {
1585 return true;
1586 }
1587 else {
1588 return false;
1589 }
1590 }
1591
1592 private static Map<String, List<String>> _errorMessagesMap =
1593 new HashMap<String, List<String>>();
1594 private static boolean _printErrors;
1595
1596 private boolean _autoFix;
1597 private Map<String, String> _compatClassNamesMap;
1598 private String _copyright;
1599 private String[] _excludes;
1600 private SourceMismatchException _firstSourceMismatchException;
1601 private String _mainReleaseVersion;
1602 private String _oldCopyright;
1603 private Properties _portalLanguageProperties;
1604 private Properties _properties;
1605 private List<String> _runOutsidePortalExclusions;
1606 private boolean _usePortalCompatImport;
1607
1608 }