001    /**
002     * Copyright (c) 2000-present 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.StringPool;
020    import com.liferay.portal.kernel.util.StringUtil;
021    import com.liferay.portal.kernel.util.Tuple;
022    import com.liferay.portal.kernel.util.Validator;
023    
024    import java.util.ArrayList;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.Set;
028    import java.util.TreeSet;
029    import java.util.regex.Matcher;
030    import java.util.regex.Pattern;
031    
032    /**
033     * @author Hugo Huijser
034     */
035    public class JavaClass {
036    
037            public static final int[] TYPE_CLASS = {
038                    JavaClass.TYPE_CLASS_PRIVATE, JavaClass.TYPE_CLASS_PRIVATE_STATIC,
039                    JavaClass.TYPE_CLASS_PROTECTED, JavaClass.TYPE_CLASS_PROTECTED_STATIC,
040                    JavaClass.TYPE_CLASS_PUBLIC, JavaClass.TYPE_CLASS_PUBLIC_STATIC
041            };
042    
043            public static final int TYPE_CLASS_PRIVATE = 24;
044    
045            public static final int TYPE_CLASS_PRIVATE_STATIC = 23;
046    
047            public static final int TYPE_CLASS_PROTECTED = 16;
048    
049            public static final int TYPE_CLASS_PROTECTED_STATIC = 15;
050    
051            public static final int TYPE_CLASS_PUBLIC = 8;
052    
053            public static final int TYPE_CLASS_PUBLIC_STATIC = 7;
054    
055            public static final int[] TYPE_CONSTRUCTOR = {
056                    JavaClass.TYPE_CONSTRUCTOR_PRIVATE,
057                    JavaClass.TYPE_CONSTRUCTOR_PROTECTED, JavaClass.TYPE_CONSTRUCTOR_PUBLIC
058            };
059    
060            public static final int TYPE_CONSTRUCTOR_PRIVATE = 18;
061    
062            public static final int TYPE_CONSTRUCTOR_PROTECTED = 10;
063    
064            public static final int TYPE_CONSTRUCTOR_PUBLIC = 4;
065    
066            public static final int[] TYPE_METHOD = {
067                    JavaClass.TYPE_METHOD_PRIVATE, JavaClass.TYPE_METHOD_PRIVATE_STATIC,
068                    JavaClass.TYPE_METHOD_PROTECTED, JavaClass.TYPE_METHOD_PROTECTED_STATIC,
069                    JavaClass.TYPE_METHOD_PUBLIC, JavaClass.TYPE_METHOD_PUBLIC_STATIC
070            };
071    
072            public static final int TYPE_METHOD_PRIVATE = 19;
073    
074            public static final int TYPE_METHOD_PRIVATE_STATIC = 17;
075    
076            public static final int TYPE_METHOD_PROTECTED = 11;
077    
078            public static final int TYPE_METHOD_PROTECTED_STATIC = 9;
079    
080            public static final int TYPE_METHOD_PUBLIC = 5;
081    
082            public static final int TYPE_METHOD_PUBLIC_STATIC = 3;
083    
084            public static final int TYPE_STATIC_BLOCK = 21;
085    
086            public static final int[] TYPE_VARIABLE = {
087                    JavaClass.TYPE_VARIABLE_PRIVATE, JavaClass.TYPE_VARIABLE_PRIVATE_STATIC,
088                    JavaClass.TYPE_VARIABLE_PROTECTED,
089                    JavaClass.TYPE_VARIABLE_PROTECTED_STATIC,
090                    JavaClass.TYPE_VARIABLE_PUBLIC, JavaClass.TYPE_VARIABLE_PUBLIC_STATIC,
091            };
092    
093            public static final int TYPE_VARIABLE_PRIVATE = 22;
094    
095            public static final int TYPE_VARIABLE_PRIVATE_STATIC = 20;
096    
097            public static final int TYPE_VARIABLE_PROTECTED = 14;
098    
099            public static final int TYPE_VARIABLE_PROTECTED_STATIC = 12;
100    
101            public static final int TYPE_VARIABLE_PUBLIC = 6;
102    
103            public static final int TYPE_VARIABLE_PUBLIC_STATIC = 1;
104    
105            public static final int[] TYPE_VARIABLE_STATIC = {
106                    JavaClass.TYPE_VARIABLE_PRIVATE_STATIC,
107                    JavaClass.TYPE_VARIABLE_PROTECTED_STATIC,
108                    JavaClass.TYPE_VARIABLE_PUBLIC_STATIC
109            };
110    
111            public JavaClass(
112                            String fileName, String absolutePath, String content, int lineCount,
113                            String indent)
114                    throws Exception {
115    
116                    _fileName = fileName;
117                    _absolutePath = absolutePath;
118                    _content = content;
119                    _lineCount = lineCount;
120                    _indent = indent;
121    
122                    _staticBlocks = new ArrayList<JavaTerm>();
123            }
124    
125            public String formatJavaTerms(
126                            List<String> javaTermAccessLevelModifierExclusions,
127                            List<String> javaTermSortExclusions,
128                            List<String> testAnnotationsExclusions)
129                    throws Exception {
130    
131                    Set<JavaTerm> javaTerms = getJavaTerms(
132                            javaTermAccessLevelModifierExclusions);
133    
134                    if (javaTerms == null) {
135                            return _content;
136                    }
137    
138                    String originalContent = _content;
139    
140                    javaTerms = addStaticBlocks(javaTerms);
141    
142                    if (!originalContent.equals(_content)) {
143                            return _content;
144                    }
145    
146                    JavaTerm previousJavaTerm = null;
147    
148                    Iterator<JavaTerm> itr = javaTerms.iterator();
149    
150                    while (itr.hasNext()) {
151                            JavaTerm javaTerm = itr.next();
152    
153                            if (isInJavaTermTypeGroup(javaTerm.getType(), TYPE_CLASS)) {
154                                    String javaTermContent = javaTerm.getContent();
155    
156                                    int pos = javaTermContent.indexOf("\n" + _indent + "static {");
157    
158                                    if (pos != -1) {
159                                            javaTermContent = javaTermContent.substring(0, pos);
160                                    }
161    
162                                    JavaClass innerClass = new JavaClass(
163                                            _fileName, _absolutePath, javaTermContent,
164                                            javaTerm.getLineCount(), _indent + StringPool.TAB);
165    
166                                    String newJavaTermContent = innerClass.formatJavaTerms(
167                                            javaTermAccessLevelModifierExclusions,
168                                            javaTermSortExclusions, testAnnotationsExclusions);
169    
170                                    if (!javaTermContent.equals(newJavaTermContent)) {
171                                            _content = StringUtil.replace(
172                                                    _content, javaTermContent, newJavaTermContent);
173    
174                                            return _content;
175                                    }
176                            }
177    
178                            sortJavaTerms(previousJavaTerm, javaTerm, javaTermSortExclusions);
179                            fixTabsAndIncorrectEmptyLines(javaTerm);
180                            formatAnnotations(javaTerm, testAnnotationsExclusions);
181    
182                            if (!originalContent.equals(_content)) {
183                                    return _content;
184                            }
185    
186                            previousJavaTerm = javaTerm;
187                    }
188    
189                    fixJavaTermsDividers(javaTerms, javaTermSortExclusions);
190    
191                    return _content;
192            }
193    
194            protected static boolean isInJavaTermTypeGroup(
195                    int javaTermType, int[] javaTermTypeGroup) {
196    
197                    for (int type : javaTermTypeGroup) {
198                            if (javaTermType == type) {
199                                    return true;
200                            }
201                    }
202    
203                    return false;
204            }
205    
206            protected Set<JavaTerm> addStaticBlocks(Set<JavaTerm> javaTerms) {
207                    Set<JavaTerm> newJavaTerms = new TreeSet<JavaTerm>(
208                            new JavaTermComparator());
209    
210                    Iterator<JavaTerm> javaTermsIterator = javaTerms.iterator();
211    
212                    while (javaTermsIterator.hasNext()) {
213                            JavaTerm javaTerm = javaTermsIterator.next();
214    
215                            if (!isInJavaTermTypeGroup(
216                                            javaTerm.getType(), TYPE_VARIABLE_STATIC)) {
217    
218                                    newJavaTerms.add(javaTerm);
219    
220                                    continue;
221                            }
222    
223                            Iterator<JavaTerm> staticBlocksIterator = _staticBlocks.iterator();
224    
225                            while (staticBlocksIterator.hasNext()) {
226                                    JavaTerm staticBlock = staticBlocksIterator.next();
227    
228                                    String staticBlockContent = staticBlock.getContent();
229    
230                                    if (staticBlockContent.contains(javaTerm.getName())) {
231                                            staticBlock.setType(javaTerm.getType() + 1);
232    
233                                            newJavaTerms.add(staticBlock);
234    
235                                            staticBlocksIterator.remove();
236                                    }
237                            }
238    
239                            newJavaTerms.add(javaTerm);
240                    }
241    
242                    if (!_staticBlocks.isEmpty()) {
243                            newJavaTerms.addAll(_staticBlocks);
244                    }
245    
246                    return newJavaTerms;
247            }
248    
249            protected void checkAnnotationForMethod(
250                    JavaTerm javaTerm, String annotation, String requiredMethodNameRegex,
251                    int requiredMethodType, String fileName) {
252    
253                    String methodContent = javaTerm.getContent();
254                    String methodName = javaTerm.getName();
255    
256                    Pattern pattern = Pattern.compile(requiredMethodNameRegex);
257    
258                    Matcher matcher = pattern.matcher(methodName);
259    
260                    if (methodContent.contains(
261                                    _indent + StringPool.AT + annotation + "\n") ||
262                            methodContent.contains(
263                                    _indent + StringPool.AT + annotation +
264                                            StringPool.OPEN_PARENTHESIS)) {
265    
266                            if (!matcher.find()) {
267                                    BaseSourceProcessor.processErrorMessage(
268                                            fileName,
269                                            "LPS-36303: Incorrect method name: " + methodName + " " +
270                                                    fileName);
271                            }
272                            else if (javaTerm.getType() != requiredMethodType) {
273                                    BaseSourceProcessor.processErrorMessage(
274                                            fileName,
275                                            "LPS-36303: Incorrect method type for " + methodName + " " +
276                                                    fileName);
277                            }
278                    }
279                    else if (matcher.find() &&
280                                     !methodContent.contains(_indent + "@Override")) {
281    
282                            BaseSourceProcessor.processErrorMessage(
283                                    fileName,
284                                    "Annotation @" + annotation + " required for " + methodName +
285                                            " " + fileName);
286                    }
287            }
288    
289            protected void checkTestAnnotations(JavaTerm javaTerm) {
290                    int methodType = javaTerm.getType();
291    
292                    if ((methodType != TYPE_METHOD_PUBLIC) &&
293                            (methodType != TYPE_METHOD_PUBLIC_STATIC)) {
294    
295                            return;
296                    }
297    
298                    checkAnnotationForMethod(
299                            javaTerm, "After", "^.*tearDown\\z", TYPE_METHOD_PUBLIC, _fileName);
300                    checkAnnotationForMethod(
301                            javaTerm, "AfterClass", "^.*tearDownClass\\z",
302                            TYPE_METHOD_PUBLIC_STATIC, _fileName);
303                    checkAnnotationForMethod(
304                            javaTerm, "Before", "^.*setUp\\z", TYPE_METHOD_PUBLIC, _fileName);
305                    checkAnnotationForMethod(
306                            javaTerm, "BeforeClass", "^.*setUpClass\\z",
307                            TYPE_METHOD_PUBLIC_STATIC, _fileName);
308                    checkAnnotationForMethod(
309                            javaTerm, "Test", "^.*test", TYPE_METHOD_PUBLIC, _fileName);
310            }
311    
312            protected void fixJavaTermsDividers(
313                    Set<JavaTerm> javaTerms, List<String> javaTermSortExclusions) {
314    
315                    JavaTerm previousJavaTerm = null;
316    
317                    Iterator<JavaTerm> itr = javaTerms.iterator();
318    
319                    while (itr.hasNext()) {
320                            JavaTerm javaTerm = itr.next();
321    
322                            if (previousJavaTerm == null) {
323                                    previousJavaTerm = javaTerm;
324    
325                                    continue;
326                            }
327    
328                            String javaTermContent = javaTerm.getContent();
329    
330                            if (javaTermContent.startsWith(_indent + "//")) {
331                                    previousJavaTerm = javaTerm;
332    
333                                    continue;
334                            }
335    
336                            String previousJavaTermContent = previousJavaTerm.getContent();
337    
338                            if (previousJavaTermContent.startsWith(_indent + "//")) {
339                                    previousJavaTerm = javaTerm;
340    
341                                    continue;
342                            }
343    
344                            String javaTermName = javaTerm.getName();
345    
346                            if (BaseSourceProcessor.isExcluded(
347                                            javaTermSortExclusions, _absolutePath,
348                                            javaTerm.getLineCount(), javaTermName)) {
349    
350                                    previousJavaTerm = javaTerm;
351    
352                                    continue;
353                            }
354    
355                            String previousJavaTermName = previousJavaTerm.getName();
356    
357                            boolean requiresEmptyLine = false;
358    
359                            if (previousJavaTerm.getType() != javaTerm.getType()) {
360                                    requiresEmptyLine = true;
361                            }
362                            else if (!isInJavaTermTypeGroup(
363                                                    javaTerm.getType(), TYPE_VARIABLE)) {
364    
365                                    requiresEmptyLine = true;
366                            }
367                            else if ((StringUtil.isUpperCase(javaTermName) &&
368                                              !StringUtil.isLowerCase(javaTermName)) ||
369                                             (StringUtil.isUpperCase(previousJavaTermName) &&
370                                              !StringUtil.isLowerCase(previousJavaTermName))) {
371    
372                                    requiresEmptyLine = true;
373                            }
374                            else if (hasAnnotationCommentOrJavadoc(javaTermContent) ||
375                                             hasAnnotationCommentOrJavadoc(previousJavaTermContent)) {
376    
377                                    requiresEmptyLine = true;
378                            }
379                            else if ((previousJavaTerm.getType() ==
380                                                    TYPE_VARIABLE_PRIVATE_STATIC) &&
381                                             (previousJavaTermName.equals("_instance") ||
382                                              previousJavaTermName.equals("_log") ||
383                                              previousJavaTermName.equals("_logger"))) {
384    
385                                    requiresEmptyLine = true;
386                            }
387                            else if (previousJavaTermContent.contains("\n\n\t") ||
388                                             javaTermContent.contains("\n\n\t")) {
389    
390                                    requiresEmptyLine = true;
391                            }
392    
393                            if (requiresEmptyLine) {
394                                    if (!_content.contains("\n\n" + javaTermContent)) {
395                                            _content = StringUtil.replace(
396                                                    _content, "\n" + javaTermContent,
397                                                    "\n\n" + javaTermContent);
398    
399                                            return;
400                                    }
401                            }
402                            else if (_content.contains("\n\n" + javaTermContent)) {
403                                    _content = StringUtil.replace(
404                                            _content, "\n\n" + javaTermContent, "\n" + javaTermContent);
405    
406                                    return;
407                            }
408    
409                            previousJavaTerm = javaTerm;
410                    }
411            }
412    
413            protected String fixLeadingTabs(
414                    String content, String line, int expectedTabCount) {
415    
416                    int leadingTabCount = JavaSourceProcessor.getLeadingTabCount(line);
417    
418                    String newLine = line;
419    
420                    while (leadingTabCount != expectedTabCount) {
421                            if (leadingTabCount > expectedTabCount) {
422                                    newLine = StringUtil.replaceFirst(
423                                            newLine, StringPool.TAB, StringPool.BLANK);
424    
425                                    leadingTabCount--;
426                            }
427                            else {
428                                    newLine = StringPool.TAB + newLine;
429    
430                                    leadingTabCount++;
431                            }
432                    }
433    
434                    return StringUtil.replace(content, line, newLine);
435            }
436    
437            protected void fixTabsAndIncorrectEmptyLines(JavaTerm javaTerm) {
438                    if (!isInJavaTermTypeGroup(javaTerm.getType(), TYPE_METHOD)) {
439                            return;
440                    }
441    
442                    String javaTermContent = "\n" + javaTerm.getContent();
443    
444                    Pattern methodNameAndParametersPattern = Pattern.compile(
445                            "\n" + _indent + "(private |protected |public )(.|\n)*?(\\{|;)\n");
446    
447                    Matcher matcher = methodNameAndParametersPattern.matcher(
448                            javaTermContent);
449    
450                    if (!matcher.find()) {
451                            return;
452                    }
453    
454                    String methodNameAndParameters = matcher.group();
455    
456                    String[] lines = StringUtil.splitLines(methodNameAndParameters);
457    
458                    if (lines.length == 1) {
459                            if (methodNameAndParameters.endsWith("{\n") &&
460                                    javaTermContent.contains(methodNameAndParameters + "\n") &&
461                                    !javaTermContent.contains(
462                                            methodNameAndParameters + "\n" + _indent + StringPool.TAB +
463                                                    "/*") &&
464                                    !javaTermContent.contains(
465                                            methodNameAndParameters + "\n" + _indent + StringPool.TAB +
466                                                    "// ")) {
467    
468                                    String trimmedJavaTermContent = StringUtil.trimTrailing(
469                                            javaTermContent);
470    
471                                    if (!trimmedJavaTermContent.endsWith(
472                                                    "\n\n" + _indent + StringPool.CLOSE_CURLY_BRACE)) {
473    
474                                            _content = StringUtil.replace(
475                                                    _content, methodNameAndParameters + "\n",
476                                                    methodNameAndParameters);
477                                    }
478                            }
479    
480                            return;
481                    }
482    
483                    if (methodNameAndParameters.endsWith("{\n") &&
484                            !javaTermContent.contains(methodNameAndParameters + "\n") &&
485                            !javaTermContent.contains(
486                                    methodNameAndParameters + _indent +
487                                            StringPool.CLOSE_CURLY_BRACE)) {
488    
489                            _content = StringUtil.replace(
490                                    _content, methodNameAndParameters,
491                                    methodNameAndParameters + "\n");
492                    }
493    
494                    boolean throwsException = methodNameAndParameters.contains(
495                            _indent + "throws ");
496    
497                    String newMethodNameAndParameters = methodNameAndParameters;
498    
499                    int expectedTabCount = -1;
500    
501                    for (int i = 0; i < lines.length; i++) {
502                            String line = lines[i];
503    
504                            if (line.contains(_indent + "throws ")) {
505                                    newMethodNameAndParameters = fixLeadingTabs(
506                                            newMethodNameAndParameters, line, _indent.length() + 1);
507    
508                                    break;
509                            }
510    
511                            if (expectedTabCount == -1) {
512                                    if (line.endsWith(StringPool.OPEN_PARENTHESIS)) {
513                                            expectedTabCount =
514                                                    Math.max(
515                                                            JavaSourceProcessor.getLeadingTabCount(line),
516                                                            _indent.length()) +
517                                                                    1;
518    
519                                            if (throwsException &&
520                                                    (expectedTabCount == (_indent.length() + 1))) {
521    
522                                                    expectedTabCount += 1;
523                                            }
524                                    }
525                            }
526                            else {
527                                    String previousLine = lines[i - 1];
528    
529                                    if (previousLine.endsWith(StringPool.COMMA) ||
530                                            previousLine.endsWith(StringPool.OPEN_PARENTHESIS)) {
531    
532                                            newMethodNameAndParameters = fixLeadingTabs(
533                                                    newMethodNameAndParameters, line, expectedTabCount);
534                                    }
535                                    else {
536                                            newMethodNameAndParameters = fixLeadingTabs(
537                                                    newMethodNameAndParameters, line,
538                                                    JavaSourceProcessor.getLeadingTabCount(previousLine) +
539                                                            1);
540                                    }
541                            }
542                    }
543    
544                    _content = StringUtil.replace(
545                            _content, methodNameAndParameters, newMethodNameAndParameters);
546            }
547    
548            protected void formatAnnotations(
549                            JavaTerm javaTerm, List<String> testAnnotationsExclusions)
550                    throws Exception {
551    
552                    if ((_indent.length() == 1) && _fileName.contains("/test/") &&
553                            !BaseSourceProcessor.isExcluded(
554                                    testAnnotationsExclusions, _absolutePath) &&
555                            !_fileName.endsWith("TestCase.java")) {
556    
557                            checkTestAnnotations(javaTerm);
558                    }
559    
560                    String javaTermContent = javaTerm.getContent();
561    
562                    String newJavaTermContent = JavaSourceProcessor.sortAnnotations(
563                            javaTermContent, _indent);
564    
565                    if (!javaTermContent.equals(newJavaTermContent)) {
566                            _content = _content.replace(javaTermContent, newJavaTermContent);
567                    }
568            }
569    
570            protected String getClassName(String line) {
571                    int pos = line.indexOf(" extends ");
572    
573                    if (pos == -1) {
574                            pos = line.indexOf(" implements ");
575                    }
576    
577                    if (pos == -1) {
578                            pos = line.indexOf(StringPool.OPEN_CURLY_BRACE);
579                    }
580    
581                    if (pos != -1) {
582                            line = line.substring(0, pos);
583                    }
584    
585                    pos = line.indexOf(StringPool.LESS_THAN);
586    
587                    if (pos != -1) {
588                            line = line.substring(0, pos);
589                    }
590    
591                    line = line.trim();
592    
593                    pos = line.lastIndexOf(StringPool.SPACE);
594    
595                    return line.substring(pos + 1);
596            }
597    
598            protected String getConstructorOrMethodName(String line, int pos) {
599                    line = line.substring(0, pos);
600    
601                    int x = line.lastIndexOf(StringPool.SPACE);
602    
603                    return line.substring(x + 1);
604            }
605    
606            protected Set<JavaTerm> getJavaTerms(
607                            List<String> javaTermAccessLevelModifierExclusions)
608                    throws Exception {
609    
610                    Set<JavaTerm> javaTerms = new TreeSet<JavaTerm>(
611                            new JavaTermComparator(false));
612    
613                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
614                            new UnsyncStringReader(_content));
615    
616                    int index = 0;
617                    int lineCount = _lineCount - 1;
618    
619                    String line = null;
620    
621                    JavaTerm javaTerm = null;
622    
623                    String javaTermName = null;
624                    int javaTermLineCount = -1;
625                    int javaTermStartPosition = -1;
626                    int javaTermType = -1;
627    
628                    int lastCommentOrAnnotationPos = -1;
629    
630                    while ((line = unsyncBufferedReader.readLine()) != null) {
631                            lineCount++;
632    
633                            if (JavaSourceProcessor.getLeadingTabCount(line) !=
634                                            _indent.length()) {
635    
636                                    index = index + line.length() + 1;
637    
638                                    continue;
639                            }
640    
641                            if (line.startsWith(_indent + "private ") ||
642                                    line.equals(_indent + "private") ||
643                                    line.startsWith(_indent + "protected ") ||
644                                    line.equals(_indent + "protected") ||
645                                    line.startsWith(_indent + "public ") ||
646                                    line.equals(_indent + "public") ||
647                                    line.equals(_indent + "static {")) {
648    
649                                    Tuple tuple = getJavaTermTuple(line, _content, index);
650    
651                                    if (tuple == null) {
652                                            return null;
653                                    }
654    
655                                    int javaTermEndPosition = 0;
656    
657                                    if (lastCommentOrAnnotationPos == -1) {
658                                            javaTermEndPosition = index;
659                                    }
660                                    else {
661                                            javaTermEndPosition = lastCommentOrAnnotationPos;
662                                    }
663    
664                                    if ((javaTermStartPosition != -1) &&
665                                            (javaTermEndPosition < _content.length())) {
666    
667                                            String javaTermContent = _content.substring(
668                                                    javaTermStartPosition, javaTermEndPosition);
669    
670                                            if (!isValidJavaTerm(javaTermContent)) {
671                                                    return null;
672                                            }
673    
674                                            if (Validator.isNotNull(javaTermName)) {
675                                                    javaTerm = new JavaTerm(
676                                                            javaTermName, javaTermType, javaTermContent,
677                                                            javaTermLineCount);
678    
679                                                    if (javaTermType == JavaClass.TYPE_STATIC_BLOCK) {
680                                                            _staticBlocks.add(javaTerm);
681                                                    }
682                                                    else {
683                                                            javaTerms.add(javaTerm);
684                                                    }
685                                            }
686                                    }
687    
688                                    javaTermLineCount = lineCount;
689                                    javaTermName = (String)tuple.getObject(0);
690                                    javaTermStartPosition = javaTermEndPosition;
691                                    javaTermType = (Integer)tuple.getObject(1);
692    
693                                    lastCommentOrAnnotationPos = -1;
694                            }
695                            else if (hasAnnotationCommentOrJavadoc(line)) {
696                                    if (lastCommentOrAnnotationPos == -1) {
697                                            lastCommentOrAnnotationPos = index;
698                                    }
699                            }
700                            else if (!line.startsWith(_indent + StringPool.CLOSE_CURLY_BRACE) &&
701                                             !line.startsWith(_indent + StringPool.CLOSE_PARENTHESIS) &&
702                                             !line.startsWith(_indent + "extends") &&
703                                             !line.startsWith(_indent + "implements") &&
704                                             !BaseSourceProcessor.isExcluded(
705                                                     javaTermAccessLevelModifierExclusions, _absolutePath,
706                                                     lineCount)) {
707    
708                                    Matcher matcher = _classPattern.matcher(_content);
709    
710                                    if (matcher.find()) {
711                                            String insideClass = _content.substring(matcher.end());
712    
713                                            if (insideClass.contains(line)) {
714                                                    BaseSourceProcessor.processErrorMessage(
715                                                            _fileName,
716                                                            "Missing access level modifier: " + _fileName +
717                                                                    " " + lineCount);
718                                            }
719                                    }
720                            }
721    
722                            index = index + line.length() + 1;
723                    }
724    
725                    if (javaTermStartPosition != -1) {
726                            int javaTermEndPosition =
727                                    _content.lastIndexOf(StringPool.CLOSE_CURLY_BRACE) -
728                                            _indent.length();
729    
730                            String javaTermContent = _content.substring(
731                                    javaTermStartPosition, javaTermEndPosition);
732    
733                            if (!isValidJavaTerm(javaTermContent)) {
734                                    return null;
735                            }
736    
737                            javaTerm = new JavaTerm(
738                                    javaTermName, javaTermType, javaTermContent, javaTermLineCount);
739    
740                            if (javaTermType == JavaClass.TYPE_STATIC_BLOCK) {
741                                    _staticBlocks.add(javaTerm);
742                            }
743                            else {
744                                    javaTerms.add(javaTerm);
745                            }
746                    }
747    
748                    return javaTerms;
749            }
750    
751            protected Tuple getJavaTermTuple(String line, String content, int index) {
752                    int posStartNextLine = index;
753    
754                    while (!line.endsWith(StringPool.OPEN_CURLY_BRACE) &&
755                               !line.endsWith(StringPool.SEMICOLON)) {
756    
757                            posStartNextLine =
758                                    content.indexOf(StringPool.NEW_LINE, posStartNextLine) + 1;
759    
760                            int posEndNextline = content.indexOf(
761                                    StringPool.NEW_LINE, posStartNextLine);
762    
763                            String nextLine = content.substring(
764                                    posStartNextLine, posEndNextline);
765    
766                            nextLine = StringUtil.trimLeading(nextLine);
767    
768                            if (line.endsWith(StringPool.OPEN_PARENTHESIS)) {
769                                    line += nextLine;
770                            }
771                            else {
772                                    line += StringPool.SPACE + nextLine;
773                            }
774                    }
775    
776                    line = StringUtil.replace(line, " synchronized " , StringPool.SPACE);
777    
778                    int pos = line.indexOf(StringPool.OPEN_PARENTHESIS);
779    
780                    if (line.startsWith(_indent + "public static ")) {
781                            if (line.contains(" class ") || line.contains(" enum ")) {
782                                    return new Tuple(getClassName(line), TYPE_CLASS_PUBLIC_STATIC);
783                            }
784    
785                            if (line.contains(StringPool.EQUAL) ||
786                                    (line.endsWith(StringPool.SEMICOLON) && (pos == -1))) {
787    
788                                    return new Tuple(
789                                            getVariableName(line), TYPE_VARIABLE_PUBLIC_STATIC);
790                            }
791    
792                            if (pos != -1) {
793                                    return new Tuple(
794                                            getConstructorOrMethodName(line, pos),
795                                            TYPE_METHOD_PUBLIC_STATIC);
796                            }
797                    }
798                    else if (line.startsWith(_indent + "public ")) {
799                            if (line.contains(" @interface ") || line.contains(" class ") ||
800                                    line.contains(" enum ") || line.contains(" interface ")) {
801    
802                                    return new Tuple(getClassName(line), TYPE_CLASS_PUBLIC);
803                            }
804    
805                            if (line.contains(StringPool.EQUAL) ||
806                                    (line.endsWith(StringPool.SEMICOLON) && (pos == -1))) {
807    
808                                    return new Tuple(getVariableName(line), TYPE_VARIABLE_PUBLIC);
809                            }
810    
811                            if (pos != -1) {
812                                    int spaceCount = StringUtil.count(
813                                            line.substring(0, pos), StringPool.SPACE);
814    
815                                    if (spaceCount == 1) {
816                                            return new Tuple(
817                                                    getConstructorOrMethodName(line, pos),
818                                                    TYPE_CONSTRUCTOR_PUBLIC);
819                                    }
820    
821                                    if (spaceCount > 1) {
822                                            return new Tuple(
823                                                    getConstructorOrMethodName(line, pos),
824                                                    TYPE_METHOD_PUBLIC);
825                                    }
826                            }
827                    }
828                    else if (line.startsWith(_indent + "protected static ")) {
829                            if (line.contains(" class ") || line.contains(" enum ")) {
830                                    return new Tuple(
831                                            getClassName(line), TYPE_CLASS_PROTECTED_STATIC);
832                            }
833    
834                            if (line.contains(StringPool.EQUAL) ||
835                                    (line.endsWith(StringPool.SEMICOLON) && (pos == -1))) {
836    
837                                    return new Tuple(
838                                            getVariableName(line), TYPE_VARIABLE_PROTECTED_STATIC);
839                            }
840    
841                            if (pos != -1) {
842                                    return new Tuple(
843                                            getConstructorOrMethodName(line, pos),
844                                            TYPE_METHOD_PROTECTED_STATIC);
845                            }
846                    }
847                    else if (line.startsWith(_indent + "protected ")) {
848                            if (line.contains(" @interface ") || line.contains(" class ") ||
849                                    line.contains(" enum ") || line.contains(" interface ")) {
850    
851                                    return new Tuple(getClassName(line), TYPE_CLASS_PROTECTED);
852                            }
853    
854                            if (pos != -1) {
855                                    if (!line.contains(StringPool.EQUAL)) {
856                                            int spaceCount = StringUtil.count(
857                                                    line.substring(0, pos), StringPool.SPACE);
858    
859                                            if (spaceCount == 1) {
860                                                    return new Tuple(
861                                                            getConstructorOrMethodName(line, pos),
862                                                            TYPE_CONSTRUCTOR_PROTECTED);
863                                            }
864    
865                                            if (spaceCount > 1) {
866                                                    return new Tuple(
867                                                            getConstructorOrMethodName(line, pos),
868                                                            TYPE_METHOD_PROTECTED);
869                                            }
870                                    }
871                            }
872    
873                            return new Tuple(getVariableName(line), TYPE_VARIABLE_PROTECTED);
874                    }
875                    else if (line.startsWith(_indent + "private static ")) {
876                            if (line.contains(" class ") || line.contains(" enum ")) {
877                                    return new Tuple(getClassName(line), TYPE_CLASS_PRIVATE_STATIC);
878                            }
879    
880                            if (line.contains(StringPool.EQUAL) ||
881                                    (line.endsWith(StringPool.SEMICOLON) && (pos == -1))) {
882    
883                                    return new Tuple(
884                                            getVariableName(line), TYPE_VARIABLE_PRIVATE_STATIC);
885                            }
886    
887                            if (pos != -1) {
888                                    return new Tuple(
889                                            getConstructorOrMethodName(line, pos),
890                                            TYPE_METHOD_PRIVATE_STATIC);
891                            }
892                    }
893                    else if (line.startsWith(_indent + "private ")) {
894                            if (line.contains(" @interface ") || line.contains(" class ") ||
895                                    line.contains(" enum ") || line.contains(" interface ")) {
896    
897                                    return new Tuple(getClassName(line), TYPE_CLASS_PRIVATE);
898                            }
899    
900                            if (line.contains(StringPool.EQUAL) ||
901                                    (line.endsWith(StringPool.SEMICOLON) && (pos == -1))) {
902    
903                                    return new Tuple(getVariableName(line), TYPE_VARIABLE_PRIVATE);
904                            }
905    
906                            if (pos != -1) {
907                                    int spaceCount = StringUtil.count(
908                                            line.substring(0, pos), StringPool.SPACE);
909    
910                                    if (spaceCount == 1) {
911                                            return new Tuple(
912                                                    getConstructorOrMethodName(line, pos),
913                                                    TYPE_CONSTRUCTOR_PRIVATE);
914                                    }
915    
916                                    if (spaceCount > 1) {
917                                            return new Tuple(
918                                                    getConstructorOrMethodName(line, pos),
919                                                    TYPE_METHOD_PRIVATE);
920                                    }
921                            }
922                    }
923                    else if (line.startsWith(_indent + "static {")) {
924                            return new Tuple("static", TYPE_STATIC_BLOCK);
925                    }
926    
927                    return null;
928            }
929    
930            protected String getVariableName(String line) {
931                    int x = line.indexOf(StringPool.EQUAL);
932                    int y = line.lastIndexOf(StringPool.SPACE);
933    
934                    if (x != -1) {
935                            line = line.substring(0, x);
936                            line = StringUtil.trim(line);
937    
938                            y = line.lastIndexOf(StringPool.SPACE);
939    
940                            return line.substring(y + 1);
941                    }
942    
943                    if (line.endsWith(StringPool.SEMICOLON)) {
944                            return line.substring(y + 1, line.length() - 1);
945                    }
946    
947                    return StringPool.BLANK;
948            }
949    
950            protected boolean hasAnnotationCommentOrJavadoc(String s) {
951                    if (s.startsWith(_indent + StringPool.AT) ||
952                            s.startsWith(_indent + StringPool.SLASH) ||
953                            s.startsWith(_indent + " *")) {
954    
955                            return true;
956                    }
957                    else {
958                            return false;
959                    }
960            }
961    
962            protected boolean isValidJavaTerm(String content) {
963                    if (content.startsWith(_indent + "static {")) {
964                            return true;
965                    }
966    
967                    while (!content.startsWith(_indent + "private") &&
968                               !content.startsWith(_indent + "protected") &&
969                               !content.startsWith(_indent + "public")) {
970    
971                            content = content.substring(content.indexOf("\n") + 1);
972                    }
973    
974                    int indentLinesCount =
975                            StringUtil.count(content, "\n" + _indent) -
976                                    StringUtil.count(content, "\n" + _indent + StringPool.TAB);
977    
978                    content = StringUtil.trim(content);
979    
980                    if (content.endsWith(StringPool.CLOSE_CURLY_BRACE) &&
981                            ((indentLinesCount == 1) ||
982                             (((indentLinesCount == 2) || (indentLinesCount == 3)) &&
983                              content.contains("\n" + _indent + "static {")))) {
984    
985                            return true;
986                    }
987                    else if ((content.endsWith("};") && (indentLinesCount == 1)) ||
988                                     (content.endsWith(StringPool.SEMICOLON) &&
989                                      (indentLinesCount == 0))) {
990    
991                            return true;
992                    }
993    
994                    return false;
995            }
996    
997            protected void sortJavaTerms(
998                    JavaTerm previousJavaTerm, JavaTerm javaTerm,
999                    List<String> javaTermSortExclusions) {
1000    
1001                    if (previousJavaTerm == null) {
1002                            return;
1003                    }
1004    
1005                    String javaTermName = javaTerm.getName();
1006    
1007                    if (BaseSourceProcessor.isExcluded(
1008                                    javaTermSortExclusions, _absolutePath, -1, javaTermName)) {
1009    
1010                            return;
1011                    }
1012    
1013                    if (previousJavaTerm.getLineCount() <= javaTerm.getLineCount()) {
1014                            return;
1015                    }
1016    
1017                    String previousJavaTermName = previousJavaTerm.getName();
1018    
1019                    String javaTermNameLowerCase = StringUtil.toLowerCase(javaTermName);
1020                    String previousJavaTermNameLowerCase = StringUtil.toLowerCase(
1021                            previousJavaTermName);
1022    
1023                    if (_fileName.contains("persistence") &&
1024                            ((previousJavaTermName.startsWith("doCount") &&
1025                              javaTermName.startsWith("doCount")) ||
1026                             (previousJavaTermName.startsWith("doFind") &&
1027                              javaTermName.startsWith("doFind")) ||
1028                             (previousJavaTermNameLowerCase.startsWith("count") &&
1029                              javaTermNameLowerCase.startsWith("count")) ||
1030                             (previousJavaTermNameLowerCase.startsWith("filter") &&
1031                              javaTermNameLowerCase.startsWith("filter")) ||
1032                             (previousJavaTermNameLowerCase.startsWith("find") &&
1033                              javaTermNameLowerCase.startsWith("find")) ||
1034                             (previousJavaTermNameLowerCase.startsWith("join") &&
1035                              javaTermNameLowerCase.startsWith("join")))) {
1036                    }
1037                    else {
1038                            _content = StringUtil.replaceFirst(
1039                                    _content, "\n" + javaTerm.getContent(),
1040                                    "\n" + previousJavaTerm.getContent());
1041                            _content = StringUtil.replaceLast(
1042                                    _content, "\n" + previousJavaTerm.getContent(),
1043                                    "\n" + javaTerm.getContent());
1044                    }
1045            }
1046    
1047            private String _absolutePath;
1048            private Pattern _classPattern = Pattern.compile(
1049                    "(private |protected |public )(static )*class ([\\s\\S]*?) \\{\n");
1050            private String _content;
1051            private String _fileName;
1052            private String _indent;
1053            private int _lineCount;
1054            private List<JavaTerm> _staticBlocks;
1055    
1056    }