001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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.ReleaseInfo;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.util.TextFormatter;
028    import com.liferay.portal.kernel.util.Validator;
029    import com.liferay.portal.util.FileImpl;
030    import com.liferay.portal.xml.SAXReaderImpl;
031    
032    import java.io.File;
033    import java.io.FileInputStream;
034    import java.io.FileNotFoundException;
035    import java.io.IOException;
036    import java.io.InputStream;
037    import java.net.URL;
038    
039    import java.util.ArrayList;
040    import java.util.HashMap;
041    import java.util.List;
042    import java.util.Map;
043    import java.util.Properties;
044    import java.util.regex.Matcher;
045    import java.util.regex.Pattern;
046    
047    import org.apache.tools.ant.DirectoryScanner;
048    
049    /**
050     * @author Brian Wing Shun Chan
051     * @author Igor Spasic
052     * @author Wesley Gong
053     * @author Hugo Huijser
054     */
055    public abstract class BaseSourceProcessor implements SourceProcessor {
056    
057            @Override
058            public void format(boolean useProperties, boolean throwException)
059                    throws Exception {
060    
061                    _init(useProperties, throwException);
062    
063                    doFormat();
064    
065                    sourceFormatterHelper.close();
066            }
067    
068            @Override
069            public List<String> getErrorMessages() {
070                    return _errorMessages;
071            }
072    
073            protected static String formatImports(String imports, int classStartPos)
074                    throws IOException {
075    
076                    if (imports.contains("/*") || imports.contains("*/") ||
077                            imports.contains("//")) {
078    
079                            return imports + "\n";
080                    }
081    
082                    List<String> importsList = new ArrayList<String>();
083    
084                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
085                            new UnsyncStringReader(imports));
086    
087                    String line = null;
088    
089                    while ((line = unsyncBufferedReader.readLine()) != null) {
090                            if ((line.contains("import=") || line.contains("import ")) &&
091                                    !importsList.contains(line)) {
092    
093                                    importsList.add(line);
094                            }
095                    }
096    
097                    importsList = ListUtil.sort(importsList);
098    
099                    StringBundler sb = new StringBundler();
100    
101                    String temp = null;
102    
103                    for (int i = 0; i < importsList.size(); i++) {
104                            String s = importsList.get(i);
105    
106                            int pos = s.indexOf(".");
107    
108                            pos = s.indexOf(".", pos + 1);
109    
110                            if (pos == -1) {
111                                    pos = s.indexOf(".");
112                            }
113    
114                            String packageLevel = s.substring(classStartPos, pos);
115    
116                            if ((i != 0) && !packageLevel.equals(temp)) {
117                                    sb.append("\n");
118                            }
119    
120                            temp = packageLevel;
121    
122                            sb.append(s);
123                            sb.append("\n");
124                    }
125    
126                    return sb.toString();
127            }
128    
129            protected void checkIfClauseParentheses(
130                    String ifClause, String fileName, int lineCount) {
131    
132                    int quoteCount = StringUtil.count(ifClause, StringPool.QUOTE);
133    
134                    if ((quoteCount % 2) == 1) {
135                            return;
136                    }
137    
138                    ifClause = stripQuotes(ifClause, StringPool.QUOTE);
139    
140                    ifClause = stripQuotes(ifClause, StringPool.APOSTROPHE);
141    
142                    if (ifClause.contains(StringPool.DOUBLE_SLASH) ||
143                            ifClause.contains("/*") || ifClause.contains("*/")) {
144    
145                            return;
146                    }
147    
148                    ifClause = stripRedundantParentheses(ifClause);
149    
150                    int level = 0;
151                    int max = StringUtil.count(ifClause, StringPool.OPEN_PARENTHESIS);
152                    int previousParenthesisPos = -1;
153    
154                    int[] levels = new int[max];
155    
156                    for (int i = 0; i < ifClause.length(); i++) {
157                            char c = ifClause.charAt(i);
158    
159                            if ((c == CharPool.OPEN_PARENTHESIS) ||
160                                    (c == CharPool.CLOSE_PARENTHESIS)) {
161    
162                                    if (previousParenthesisPos != -1) {
163                                            String s = ifClause.substring(
164                                                    previousParenthesisPos + 1, i);
165    
166                                            if (hasMissingParentheses(s)) {
167                                                    processErrorMessage(
168                                                            fileName,
169                                                            "missing parentheses: " + fileName + " " +
170                                                                    lineCount);
171                                            }
172                                    }
173    
174                                    previousParenthesisPos = i;
175    
176                                    if (c == CharPool.OPEN_PARENTHESIS) {
177                                            levels[level] = i;
178    
179                                            level += 1;
180                                    }
181                                    else {
182                                            int posOpenParenthesis = levels[level - 1];
183    
184                                            if (level > 1) {
185                                                    char nextChar = ifClause.charAt(i + 1);
186                                                    char previousChar = ifClause.charAt(
187                                                            posOpenParenthesis - 1);
188    
189                                                    if (!Character.isLetterOrDigit(nextChar) &&
190                                                            (nextChar != CharPool.PERIOD) &&
191                                                            !Character.isLetterOrDigit(previousChar)) {
192    
193                                                            String s = ifClause.substring(
194                                                                    posOpenParenthesis + 1, i);
195    
196                                                            if (hasRedundantParentheses(s)) {
197                                                                    processErrorMessage(
198                                                                            fileName,
199                                                                            "redundant parentheses: " + fileName + " " +
200                                                                                    lineCount);
201                                                            }
202                                                    }
203    
204                                                    if ((previousChar == CharPool.OPEN_PARENTHESIS) &&
205                                                            (nextChar == CharPool.CLOSE_PARENTHESIS)) {
206    
207                                                            processErrorMessage(
208                                                                    fileName,
209                                                                    "redundant parentheses: " + fileName + " " +
210                                                                            lineCount);
211                                                    }
212                                            }
213    
214                                            level -= 1;
215                                    }
216                            }
217                    }
218            }
219    
220            protected void checkLanguageKeys(
221                            String fileName, String content, Pattern pattern)
222                    throws IOException {
223    
224                    String fileExtension = fileUtil.getExtension(fileName);
225    
226                    if (!portalSource || fileExtension.equals("vm")) {
227                            return;
228                    }
229    
230                    if (_portalLanguageKeysProperties == null) {
231                            _portalLanguageKeysProperties = new Properties();
232    
233                            ClassLoader classLoader =
234                                    BaseSourceProcessor.class.getClassLoader();
235    
236                            InputStream inputStream = classLoader.getResourceAsStream(
237                                    "content/Language.properties");
238    
239                            _portalLanguageKeysProperties.load(inputStream);
240                    }
241    
242                    Matcher matcher = pattern.matcher(content);
243    
244                    while (matcher.find()) {
245                            String[] languageKeys = getLanguageKeys(matcher);
246    
247                            for (String languageKey : languageKeys) {
248                                    if (Validator.isNumber(languageKey) ||
249                                            languageKey.endsWith(StringPool.DASH) ||
250                                            languageKey.endsWith(StringPool.PERIOD) ||
251                                            languageKey.endsWith(StringPool.UNDERLINE) ||
252                                            languageKey.startsWith(StringPool.DASH) ||
253                                            languageKey.startsWith(StringPool.OPEN_BRACKET) ||
254                                            languageKey.startsWith(StringPool.OPEN_CURLY_BRACE) ||
255                                            languageKey.startsWith(StringPool.PERIOD) ||
256                                            languageKey.startsWith(StringPool.UNDERLINE)) {
257    
258                                            continue;
259                                    }
260    
261                                    if (!_portalLanguageKeysProperties.containsKey(languageKey)) {
262                                            processErrorMessage(
263                                                    fileName,
264                                                    "missing language key: " + languageKey +
265                                                            StringPool.SPACE + fileName);
266                                    }
267                            }
268                    }
269            }
270    
271            protected abstract void doFormat() throws Exception;
272    
273            protected String fixCompatClassImports(String fileName, String content)
274                    throws IOException {
275    
276                    if (portalSource ||
277                            !mainReleaseVersion.equals(MAIN_RELEASE_VERSION_6_1_0) ||
278                            fileName.contains("/ext-") ||
279                            fileName.contains("/portal-compat-shared/")) {
280    
281                            return content;
282                    }
283    
284                    Map<String, String> compatClassNamesMap = getCompatClassNamesMap();
285    
286                    String newContent = content;
287    
288                    for (Map.Entry<String, String> entry : compatClassNamesMap.entrySet()) {
289                            String compatClassName = entry.getKey();
290                            String extendedClassName = entry.getValue();
291    
292                            Pattern pattern = Pattern.compile(extendedClassName + "\\W");
293    
294                            for (;;) {
295                                    Matcher matcher = pattern.matcher(newContent);
296    
297                                    if (!matcher.find()) {
298                                            break;
299                                    }
300    
301                                    newContent =
302                                            newContent.substring(0, matcher.start()) + compatClassName +
303                                                    newContent.substring(matcher.end() - 1);
304                            }
305                    }
306    
307                    return newContent;
308            }
309    
310            protected String fixCopyright(
311                            String content, String copyright, String oldCopyright, File file,
312                            String fileName)
313                    throws IOException {
314    
315                    if (fileName.endsWith(".vm")) {
316                            return content;
317                    }
318    
319                    if ((oldCopyright != null) && content.contains(oldCopyright)) {
320                            content = StringUtil.replace(content, oldCopyright, copyright);
321    
322                            processErrorMessage(fileName, "old (c): " + fileName);
323                    }
324    
325                    if (!content.contains(copyright)) {
326                            String customCopyright = getCustomCopyright(file);
327    
328                            if (Validator.isNotNull(customCopyright)) {
329                                    copyright = customCopyright;
330                            }
331    
332                            if (!content.contains(copyright)) {
333                                    processErrorMessage(fileName, "(c): " + fileName);
334                            }
335                    }
336    
337                    if (fileName.endsWith(".jsp") || fileName.endsWith(".jspf")) {
338                            content = StringUtil.replace(
339                                    content, "<%\n" + copyright + "\n%>",
340                                    "<%--\n" + copyright + "\n--%>");
341                    }
342    
343                    int x = content.indexOf("* Copyright (c) 2000-20");
344    
345                    if (x == -1) {
346                            return content;
347                    }
348    
349                    int y = copyright.indexOf("* Copyright (c) 2000-20");
350    
351                    if (y == -1) {
352                            return content;
353                    }
354    
355                    String contentCopyrightYear = content.substring(x, x + 25);
356                    String copyrightYear = copyright.substring(y, y + 25);
357    
358                    return StringUtil.replace(content, contentCopyrightYear, copyrightYear);
359            }
360    
361            protected String fixSessionKey(
362                    String fileName, String content, Pattern pattern) {
363    
364                    if (mainReleaseVersion.equals(MAIN_RELEASE_VERSION_6_1_0)) {
365                            return content;
366                    }
367    
368                    Matcher matcher = pattern.matcher(content);
369    
370                    if (!matcher.find()) {
371                            return content;
372                    }
373    
374                    String newContent = content;
375    
376                    do {
377                            String match = matcher.group();
378    
379                            String s = null;
380    
381                            if (pattern.equals(sessionKeyPattern)) {
382                                    s = StringPool.COMMA;
383                            }
384                            else if (pattern.equals(taglibSessionKeyPattern)) {
385                                    s = "key=";
386                            }
387    
388                            int x = match.indexOf(s);
389    
390                            if (x == -1) {
391                                    continue;
392                            }
393    
394                            x = x + s.length();
395    
396                            String substring = match.substring(x).trim();
397    
398                            String quote = StringPool.BLANK;
399    
400                            if (substring.startsWith(StringPool.APOSTROPHE)) {
401                                    quote = StringPool.APOSTROPHE;
402                            }
403                            else if (substring.startsWith(StringPool.QUOTE)) {
404                                    quote = StringPool.QUOTE;
405                            }
406                            else {
407                                    continue;
408                            }
409    
410                            int y = match.indexOf(quote, x);
411                            int z = match.indexOf(quote, y + 1);
412    
413                            if ((y == -1) || (z == -1)) {
414                                    continue;
415                            }
416    
417                            String prefix = match.substring(0, y + 1);
418                            String suffix = match.substring(z);
419                            String oldKey = match.substring(y + 1, z);
420    
421                            boolean alphaNumericKey = true;
422    
423                            for (char c : oldKey.toCharArray()) {
424                                    if (!Validator.isChar(c) && !Validator.isDigit(c) &&
425                                            (c != CharPool.DASH) && (c != CharPool.UNDERLINE)) {
426    
427                                            alphaNumericKey = false;
428                                    }
429                            }
430    
431                            if (!alphaNumericKey) {
432                                    continue;
433                            }
434    
435                            String newKey = TextFormatter.format(oldKey, TextFormatter.O);
436    
437                            newKey = TextFormatter.format(newKey, TextFormatter.M);
438    
439                            if (newKey.equals(oldKey)) {
440                                    continue;
441                            }
442    
443                            String oldSub = prefix.concat(oldKey).concat(suffix);
444                            String newSub = prefix.concat(newKey).concat(suffix);
445    
446                            newContent = StringUtil.replaceFirst(newContent, oldSub, newSub);
447                    }
448                    while (matcher.find());
449    
450                    return newContent;
451            }
452    
453            protected Map<String, String> getCompatClassNamesMap() throws IOException {
454                    if (_compatClassNamesMap != null) {
455                            return _compatClassNamesMap;
456                    }
457    
458                    _compatClassNamesMap = new HashMap<String, String>();
459    
460                    String[] includes = new String[] {
461                            "**\\portal-compat-shared\\src\\com\\liferay\\compat\\**\\*.java"
462                    };
463    
464                    String basedir = BASEDIR;
465    
466                    List<String> fileNames = new ArrayList<String>();
467    
468                    for (int i = 0; i < 3; i++) {
469                            fileNames = getFileNames(basedir, new String[0], includes);
470    
471                            if (!fileNames.isEmpty()) {
472                                    break;
473                            }
474    
475                            basedir = "../" + basedir;
476                    }
477    
478                    for (String fileName : fileNames) {
479                            File file = new File(basedir + fileName);
480    
481                            String content = fileUtil.read(file);
482    
483                            fileName = StringUtil.replace(
484                                    fileName, StringPool.BACK_SLASH, StringPool.SLASH);
485    
486                            fileName = StringUtil.replace(
487                                    fileName, StringPool.SLASH, StringPool.PERIOD);
488    
489                            int pos = fileName.indexOf("com.");
490    
491                            String compatClassName = fileName.substring(pos);
492    
493                            compatClassName = compatClassName.substring(
494                                    0, compatClassName.length() - 5);
495    
496                            String extendedClassName = StringUtil.replace(
497                                    compatClassName, "compat.", StringPool.BLANK);
498    
499                            if (content.contains("extends " + extendedClassName)) {
500                                    _compatClassNamesMap.put(compatClassName, extendedClassName);
501                            }
502                    }
503    
504                    return _compatClassNamesMap;
505            }
506    
507            protected String getCopyright() throws IOException {
508                    String copyright = fileUtil.read("copyright.txt");
509    
510                    if (Validator.isNull(copyright)) {
511                            copyright = fileUtil.read("../copyright.txt");
512                    }
513    
514                    if (Validator.isNull(copyright)) {
515                            copyright = fileUtil.read("../../copyright.txt");
516                    }
517    
518                    return copyright;
519            }
520    
521            protected String getCustomCopyright(File file) throws IOException {
522                    String absolutePath = fileUtil.getAbsolutePath(file);
523    
524                    for (int x = absolutePath.length();;) {
525                            x = absolutePath.lastIndexOf(StringPool.SLASH, x);
526    
527                            if (x == -1) {
528                                    break;
529                            }
530    
531                            String copyright = fileUtil.read(
532                                    absolutePath.substring(0, x + 1) + "copyright.txt");
533    
534                            if (Validator.isNotNull(copyright)) {
535                                    return copyright;
536                            }
537    
538                            x = x - 1;
539                    }
540    
541                    return null;
542            }
543    
544            protected List<String> getFileNames(
545                    String basedir, String[] excludes, String[] includes) {
546    
547                    DirectoryScanner directoryScanner = new DirectoryScanner();
548    
549                    directoryScanner.setBasedir(basedir);
550    
551                    excludes = ArrayUtil.append(
552                            excludes, _excludes, new String[] {"**\\.git\\**"});
553    
554                    directoryScanner.setExcludes(excludes);
555    
556                    directoryScanner.setIncludes(includes);
557    
558                    return sourceFormatterHelper.scanForFiles(directoryScanner);
559            }
560    
561            protected List<String> getFileNames(String[] excludes, String[] includes) {
562                    return getFileNames(BASEDIR, excludes, includes);
563            }
564    
565            protected String[] getLanguageKeys(Matcher matcher) {
566                    if (matcher.groupCount() > 0) {
567                            String languageKey = matcher.group(1);
568    
569                            if (Validator.isNotNull(languageKey)) {
570                                    return new String[] {languageKey};
571                            }
572                    }
573    
574                    StringBundler sb = new StringBundler();
575    
576                    String match = matcher.group();
577    
578                    int count = 0;
579    
580                    for (int i = 0; i < match.length(); i++) {
581                            char c = match.charAt(i);
582    
583                            switch (c) {
584                                    case CharPool.CLOSE_PARENTHESIS:
585                                            if (count <= 1) {
586                                                    return new String[0];
587                                            }
588    
589                                            count--;
590    
591                                            break;
592    
593                                    case CharPool.OPEN_PARENTHESIS:
594                                            count++;
595    
596                                            break;
597    
598                                    case CharPool.QUOTE:
599                                            if (count > 1) {
600                                                    break;
601                                            }
602    
603                                            while (i < match.length()) {
604                                                    i++;
605    
606                                                    if (match.charAt(i) == CharPool.QUOTE) {
607                                                            String languageKey = sb.toString();
608    
609                                                            if (match.startsWith("names")) {
610                                                                    return StringUtil.split(languageKey);
611                                                            }
612                                                            else {
613                                                                    return new String[] {languageKey};
614                                                            }
615    
616                                                    }
617    
618                                                    sb.append(match.charAt(i));
619                                            }
620                            }
621                    }
622    
623                    return new String[0];
624            }
625    
626            protected String getOldCopyright() throws IOException {
627                    String copyright = fileUtil.read("old-copyright.txt");
628    
629                    if (Validator.isNull(copyright)) {
630                            copyright = fileUtil.read("../old-copyright.txt");
631                    }
632    
633                    if (Validator.isNull(copyright)) {
634                            copyright = fileUtil.read("../../old-copyright.txt");
635                    }
636    
637                    return copyright;
638            }
639    
640            protected Properties getExclusionsProperties(String fileName)
641                    throws IOException {
642    
643                    InputStream inputStream = null;
644    
645                    int level = 0;
646    
647                    if (portalSource) {
648                            ClassLoader classLoader =
649                                    BaseSourceProcessor.class.getClassLoader();
650    
651                            String sourceFormatterExclusions = System.getProperty(
652                                    "source-formatter-exclusions",
653                                    "com/liferay/portal/tools/dependencies/" + fileName);
654    
655                            URL url = classLoader.getResource(sourceFormatterExclusions);
656    
657                            if (url == null) {
658                                    return null;
659                            }
660    
661                            inputStream = url.openStream();
662                    }
663                    else {
664                            try {
665                                    inputStream = new FileInputStream(fileName);
666                            }
667                            catch (FileNotFoundException fnfe) {
668                            }
669    
670                            if (inputStream == null) {
671                                    try {
672                                            inputStream = new FileInputStream("../" + fileName);
673    
674                                            level = 1;
675                                    }
676                                    catch (FileNotFoundException fnfe) {
677                                    }
678                            }
679    
680                            if (inputStream == null) {
681                                    try {
682                                            inputStream = new FileInputStream("../../" + fileName);
683    
684                                            level = 2;
685                                    }
686                                    catch (FileNotFoundException fnfe) {
687                                            return null;
688                                    }
689                            }
690                    }
691    
692                    Properties properties = new Properties();
693    
694                    properties.load(inputStream);
695    
696                    inputStream.close();
697    
698                    if (level > 0) {
699                            properties = stripTopLevelDirectories(properties, level);
700                    }
701    
702                    return properties;
703            }
704    
705            protected boolean hasMissingParentheses(String s) {
706                    if (Validator.isNull(s)) {
707                            return false;
708                    }
709    
710                    boolean containsAndOrOperator = (s.contains("&&") || s.contains("||"));
711    
712                    boolean containsCompareOperator =
713                            (s.contains(" == ") || s.contains(" != ") || s.contains(" < ") ||
714                             s.contains(" > ") || s.contains(" =< ") || s.contains(" => ") ||
715                             s.contains(" <= ") || s.contains(" >= "));
716    
717                    boolean containsMathOperator =
718                            (s.contains(" = ") || s.contains(" - ") || s.contains(" + ") ||
719                             s.contains(" & ") || s.contains(" % ") || s.contains(" * ") ||
720                             s.contains(" / "));
721    
722                    if (containsCompareOperator &&
723                            (containsAndOrOperator ||
724                             (containsMathOperator && !s.contains(StringPool.OPEN_BRACKET)))) {
725    
726                            return true;
727                    }
728                    else {
729                            return false;
730                    }
731            }
732    
733            protected boolean hasRedundantParentheses(String s) {
734                    if (!s.contains("&&") && !s.contains("||")) {
735                            for (int x = 0;;) {
736                                    x = s.indexOf(StringPool.CLOSE_PARENTHESIS);
737    
738                                    if (x == -1) {
739                                            break;
740                                    }
741    
742                                    int y = s.substring(0, x).lastIndexOf(
743                                            StringPool.OPEN_PARENTHESIS);
744    
745                                    if (y == -1) {
746                                            break;
747                                    }
748    
749                                    s = s.substring(0, y) + s.substring(x + 1);
750                            }
751                    }
752    
753                    if (Validator.isNotNull(s) && !s.contains(StringPool.SPACE)) {
754                            return true;
755                    }
756                    else {
757                            return false;
758                    }
759            }
760    
761            protected void processErrorMessage(String fileName, String message) {
762                    if (_throwException) {
763                            _errorMessages.add(message);
764                    }
765                    else {
766                            sourceFormatterHelper.printError(fileName, message);
767                    }
768            }
769    
770            protected String replacePrimitiveWrapperInstantiation(
771                    String fileName, String line, int lineCount) {
772    
773                    if (true) {
774                            return line;
775                    }
776    
777                    String newLine = StringUtil.replace(
778                            line,
779                            new String[] {
780                                    "new Boolean(", "new Byte(", "new Character(", "new Integer(",
781                                    "new Long(", "new Short("
782                            },
783                            new String[] {
784                                    "Boolean.valueOf(", "Byte.valueOf(", "Character.valueOf(",
785                                    "Integer.valueOf(", "Long.valueOf(", "Short.valueOf("
786                            });
787    
788                    if (!line.equals(newLine)) {
789                            processErrorMessage(
790                                    fileName, "> new Primitive(: " + fileName + " " + lineCount);
791                    }
792    
793                    return newLine;
794            }
795    
796            protected String stripQuotes(String s, String delimeter) {
797                    String[] parts = StringUtil.split(s, delimeter);
798    
799                    int i = 1;
800    
801                    while (i < parts.length) {
802                            s = StringUtil.replaceFirst(
803                                    s, delimeter + parts[i] + delimeter, StringPool.BLANK);
804    
805                            i = i + 2;
806                    }
807    
808                    return s;
809            }
810    
811            protected String stripRedundantParentheses(String s) {
812                    for (int x = 0;;) {
813                            x = s.indexOf(StringPool.OPEN_PARENTHESIS, x + 1);
814                            int y = s.indexOf(StringPool.CLOSE_PARENTHESIS, x);
815    
816                            if ((x == -1) || (y == -1)) {
817                                    return s;
818                            }
819    
820                            String linePart = s.substring(x + 1, y);
821    
822                            linePart = StringUtil.replace(
823                                    linePart, StringPool.COMMA, StringPool.BLANK);
824    
825                            if (Validator.isAlphanumericName(linePart) ||
826                                    Validator.isNull(linePart)) {
827    
828                                    s = s.substring(0, x) + s.substring(y + 1);
829                            }
830                    }
831            }
832    
833            protected Properties stripTopLevelDirectories(
834                            Properties properties, int level)
835                    throws IOException {
836    
837                    File dir = new File(".");
838    
839                    String dirName = dir.getCanonicalPath();
840    
841                    dirName = StringUtil.replace(
842                            dirName, StringPool.BACK_SLASH, StringPool.SLASH);
843    
844                    int pos = dirName.length();
845    
846                    for (int i = 0; i < level; i++) {
847                            pos = dirName.lastIndexOf(StringPool.SLASH, pos - 1);
848                    }
849    
850                    String topLevelDirNames = dirName.substring(pos + 1) + StringPool.SLASH;
851    
852                    Properties newProperties = new Properties();
853    
854                    for (Map.Entry<Object, Object> entry : properties.entrySet()) {
855                            String key = (String)entry.getKey();
856    
857                            if (!key.startsWith(topLevelDirNames)) {
858                                    continue;
859                            }
860    
861                            key = StringUtil.replaceFirst(
862                                    key, topLevelDirNames, StringPool.BLANK);
863    
864                            String value = (String)entry.getValue();
865    
866                            newProperties.setProperty(key, value);
867                    }
868    
869                    return newProperties;
870            }
871    
872            protected String trimContent(String content, boolean allowLeadingSpaces)
873                    throws IOException {
874    
875                    StringBundler sb = new StringBundler();
876    
877                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
878                            new UnsyncStringReader(content));
879    
880                    String line = null;
881    
882                    while ((line = unsyncBufferedReader.readLine()) != null) {
883                            sb.append(trimLine(line, allowLeadingSpaces));
884                            sb.append("\n");
885                    }
886    
887                    unsyncBufferedReader.close();
888    
889                    content = sb.toString();
890    
891                    if (content.endsWith("\n")) {
892                            content = content.substring(0, content.length() - 1);
893                    }
894    
895                    return content;
896            }
897    
898            protected String trimLine(String line, boolean allowLeadingSpaces) {
899                    if (line.trim().length() == 0) {
900                            return StringPool.BLANK;
901                    }
902    
903                    line = StringUtil.trimTrailing(line);
904    
905                    if (allowLeadingSpaces || !line.startsWith(StringPool.SPACE) ||
906                            line.startsWith(" *")) {
907    
908                            return line;
909                    }
910    
911                    if (!line.startsWith(StringPool.FOUR_SPACES)) {
912                            while (line.startsWith(StringPool.SPACE)) {
913                                    line = StringUtil.replaceFirst(
914                                            line, StringPool.SPACE, StringPool.BLANK);
915                            }
916                    }
917                    else {
918                            int pos = 0;
919    
920                            String temp = line;
921    
922                            while (temp.startsWith(StringPool.FOUR_SPACES)) {
923                                    line = StringUtil.replaceFirst(
924                                            line, StringPool.FOUR_SPACES, StringPool.TAB);
925    
926                                    pos++;
927    
928                                    temp = line.substring(pos);
929                            }
930                    }
931    
932                    return line;
933            }
934    
935            protected static final String BASEDIR = "./";
936    
937            protected static final String MAIN_RELEASE_VERSION_6_1_0 = "6.1.0";
938    
939            protected static final String MAIN_RELEASE_VERSION_6_2_0 = "6.2.0";
940    
941            protected static FileImpl fileUtil = FileImpl.getInstance();
942            protected static Pattern languageKeyPattern = Pattern.compile(
943                    "LanguageUtil.(?:get|format)\\([^;%]+|Liferay.Language.get\\('([^']+)");
944            protected static String mainReleaseVersion;
945            protected static boolean portalSource;
946            protected static SAXReaderImpl saxReaderUtil = SAXReaderImpl.getInstance();
947            protected static Pattern sessionKeyPattern = Pattern.compile(
948                    "SessionErrors.(?:add|contains|get)\\([^;%&|!]+|".concat(
949                            "SessionMessages.(?:add|contains|get)\\([^;%&|!]+"),
950                    Pattern.MULTILINE);
951            protected static SourceFormatterHelper sourceFormatterHelper;
952            protected static Pattern taglibSessionKeyPattern = Pattern.compile(
953                    "<liferay-ui:error [^>]+>|<liferay-ui:success [^>]+>",
954                    Pattern.MULTILINE);
955    
956            private void _init(boolean useProperties, boolean throwException)
957                    throws Exception {
958    
959                    _errorMessages = new ArrayList<String>();
960    
961                    sourceFormatterHelper = new SourceFormatterHelper(useProperties);
962    
963                    sourceFormatterHelper.init();
964    
965                    if (_initialized) {
966                            return;
967                    }
968    
969                    _setVersion();
970    
971                    _excludes = StringUtil.split(
972                            GetterUtil.getString(
973                                    System.getProperty("source.formatter.excludes")));
974    
975                    portalSource = _isPortalSource();
976    
977                    _throwException = throwException;
978    
979                    _initialized = true;
980            }
981    
982            private boolean _isPortalSource() {
983                    if (fileUtil.exists(BASEDIR + "portal-impl")) {
984                            return true;
985                    }
986                    else {
987                            return false;
988                    }
989            }
990    
991            private void _setVersion() throws Exception {
992                    String releaseInfoVersion = ReleaseInfo.getVersion();
993    
994                    if (releaseInfoVersion.startsWith("6.1")) {
995                            mainReleaseVersion = MAIN_RELEASE_VERSION_6_1_0;
996                    }
997                    else if (releaseInfoVersion.startsWith("6.2")) {
998                            mainReleaseVersion = MAIN_RELEASE_VERSION_6_2_0;
999                    }
1000                    else {
1001                            throw new Exception(
1002                                    "Invalid release information: " + ReleaseInfo.getVersion());
1003                    }
1004            }
1005    
1006            private Map<String, String> _compatClassNamesMap;
1007            private static List<String> _errorMessages = new ArrayList<String>();
1008            private static String[] _excludes;
1009            private static boolean _initialized;
1010            private static Properties _portalLanguageKeysProperties;
1011            private static boolean _throwException;
1012    
1013    }