mergedoc.core.JavaBuffer.java Source code

Java tutorial

Introduction

Here is the source code for mergedoc.core.JavaBuffer.java

Source

/*
 * Copyright (c) 2003- Shinji Kashihara. All rights reserved.
 * This program are made available under the terms of the Common Public License
 * v1.0 which accompanies this distribution, and is available at cpl-v10.html.
 */
package mergedoc.core;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Java ???
 * @author Shinji Kashihara
 */
public class JavaBuffer {

    /**  */
    private static final Log log = LogFactory.getLog(JavaBuffer.class);

    /** class|interface|@interface|enum */
    private String classKind;

    /** ?? */
    private final String className;

    /** Java  */
    private final String source;

    /** ? */
    private static final Pattern commentPattern = PatternCache.getPattern("(?sm)^ *?/\\*\\*.*?\\*/ *?\\n?");

    /** ?? */
    private final Matcher commentMatcher;

    /** ? */
    private final StringBuffer outputBuffer = new StringBuffer();

    /** ??????? */
    private static class ClassBlock {
        final String name;
        final int end;

        ClassBlock(String name, int end) {
            this.name = name;
            this.end = end;
        }
    }

    /** ClassBlock  */
    private final Stack<ClassBlock> classStack = new Stack<ClassBlock>();

    /** ?????? */
    private static final String DUMMY_COMMENT = "/** Empty comment. " + JavaBuffer.class.getName() + ". */\n";

    /**
     * ??
     * @param classKind 
     * @param className ??
     * @param javaSource Java 
     */
    public JavaBuffer(String classKind, String className, String javaSource) {

        this.classKind = classKind;
        this.className = className;
        this.source = setupDummyComment(javaSource);
        commentMatcher = commentPattern.matcher(source);

        // ?
        ClassBlock cb = new ClassBlock(className, source.length());
        classStack.push(cb);
    }

    /**
     * Javadoc ??????
     * <p>
     * Javadoc ???? Java  nextComment ?
     * ???????????
     * ??? classBlock ?????
     * <p>
     * ????? Javadoc ???????
     * ??? Javadoc ???????Javadoc
     * ???? Javadoc API ???
     * <pre>
     * JDK1.4 javax.swing.JEditorPane ? ??
     *        JEditorPaneAccessibleHypertextSupport.HTMLLink ??
     * </pre>
     * <p>
     * JDK1.4 java.beans.beancontext.BeanContextServicesSupport#BCSSChild ?
     * /* ????????Javadoc ?????
     * Javadoc API ???????????????
     * ??????
     *
     * @param src Java 
     * @return ??
     */
    private String setupDummyComment(String src) {

        // ? Javadoc ???????
        // ??????????????
        // ?????????
        // ?
        //Matcher mat = Pattern.compile("\\{[^@]").matcher(src);
        //int pos = 0;
        //if (mat.find()) pos = mat.start();
        //String head = src.substring(0, pos);
        //String body = src.substring(pos);
        //body = body.replaceAll(
        //    "([^/\\s]( *?\n)+)((\\s*)[\\w\\s]*\\s(class|interface)\\s)",
        //    "$1$4/\\*\\*" + DUMMY_COMMENT + "\\*/\n$3");
        //return head + body;

        //----------------------------------------------------------------------
        // ????? Profiler ?????
        // ??????????? 1 ????
        // ??? 6 ??
        // ????????????
        // ? Javadoc ??????
        // ??
        //
        //   ?????
        //      JDK1.4 java.net.Authenticator ??
        //   ?????
        //      JDK1.4 javax.swing.plaf.basic.BasicTableUI ??
        //----------------------------------------------------------------------

        char[] c = src.toCharArray();
        int last = c.length - 1;
        List<Integer> dummyInsertPositions = new ArrayList<Integer>();
        int declareMaxLength = 12;

        for (int i = declareMaxLength; i <= last; i++) {

            if (c[i - 1] == '/' && c[i] == '*') {
                // ???
                for (i++; i <= last; i++) {
                    if (c[i - 1] == '*' && c[i] == '/') {
                        break;
                    }
                }
            } else if (c[i - 1] == '/' && c[i] == '/') {
                // ???
                for (i++; i <= last; i++) {
                    if (c[i] == '\n') {
                        i++;
                        break;
                    }
                }
            } else if (c[i - 1] != '\'' && c[i] == '"') {
                // ??????
                for (i++; i <= last; i++) {
                    if (c[i] == '"') {
                        if (c[i - 1] != '\\' || (c[i - 1] == '\\' && c[i - 2] == '\\')) {
                            break;
                        }
                    }
                }
            } else if (c[i - 1] != '"' && c[i] == '\'') {
                // ??????
                for (i++; i <= last; i++) {
                    if (c[i] == '\'') {
                        if (c[i - 1] != '\\' || (c[i - 1] == '\\' && c[i - 2] == '\\')) {
                            break;
                        }
                    }
                }
            }
            if (i >= last) {
                break;
            }

            // ???
            // class|interface|@interface|enum
            int declaPos = -1;
            if (c[i] == ' ' || c[i] == '\n' || c[i] == '<') {

                if (c[i - 5] == 'c' && c[i - 4] == 'l' && c[i - 3] == 'a' && c[i - 2] == 's' && c[i - 1] == 's') {
                    // class ??
                    if (c[i - 6] == ' ' || c[i - 6] == '\n') {
                        declaPos = i - 7;
                    }
                } else if (c[i - 9] == 'i' && c[i - 8] == 'n' && c[i - 7] == 't' && c[i - 6] == 'e'
                        && c[i - 5] == 'r' && c[i - 4] == 'f' && c[i - 3] == 'a' && c[i - 2] == 'c'
                        && c[i - 1] == 'e') {
                    // interface ??
                    if (c[i - 10] == ' ' || c[i - 10] == '\n') {
                        declaPos = i - 11;
                    } else if (c[i - 10] == '@') {
                        // @interface ??
                        if (c[i - 11] == ' ' || c[i - 11] == '\n') {
                            declaPos = i - 12;
                        }
                    }
                } else if (c[i - 4] == 'e' && c[i - 3] == 'n' && c[i - 2] == 'u' && c[i - 1] == 'm') {
                    // enum ??
                    if (c[i - 5] == ' ' || c[i - 5] == '\n') {
                        declaPos = i - 6;
                    }
                }
            }

            // ? Javadoc ??????
            for (int j = declaPos; j > 0; j--) {

                if (c[j - 1] == '*' && c[j] == '/') {
                    break;
                }
                if (c[j] == ';' || c[j] == '}' || c[j] == '{') {

                    for (int k = j - 1; k > 0; k--) {
                        if (c[k - 1] == '/' && c[k] == '/') {
                            break;
                        }
                        if (c[k] == '\n') {

                            for (int l = j + 1; l < i; l++) {
                                if (c[l] == '\n') {
                                    dummyInsertPositions.add(l + 1);
                                    k = -1;
                                    j = -1;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

        // ??? Javadoc ?
        StringBuilder sb = new StringBuilder(src);
        for (int i = dummyInsertPositions.size() - 1; i >= 0; i--) {
            int pos = dummyInsertPositions.get(i);
            sb.insert(pos, DUMMY_COMMENT);
        }
        return sb.toString();
    }

    /**
     * ???????
     * ?????????
     * ????????????
     * @return ????? true
     */
    public boolean nextComment() {

        while (commentMatcher.find()) {

            // ???????
            // /*******************/
            // JDK1.4 java.io.ObjectStreamConstants ??
            String sourceComment = getSourceComment();
            if (FastStringUtils.matches(sourceComment, "\\s*/\\*+/\\s*\n")) {
                continue;
            }

            // ??????
            if (sourceComment.contains(DUMMY_COMMENT)) {
                getSignature(); //??????
                commentMatcher.appendReplacement(outputBuffer, "");
                continue;
            }

            // ?????????
            Matcher nextMat = commentPattern.matcher(source);
            int currentEnd = commentMatcher.end();
            if (nextMat.find(currentEnd)) {
                String c2c = source.substring(currentEnd, nextMat.start());
                // ?(java.awt.GridBagLayoutorg.omg.PortableServer.Servant??)
                c2c = PatternCache.getPattern("(?s)/\\*(?:[^\\*].*?)?\\*/").matcher(c2c).replaceAll("");
                c2c = PatternCache.getPattern("//.*").matcher(c2c).replaceAll("");
                if (FastStringUtils.matches(c2c, "\\s*")) {
                    continue;
                }
            }

            return true;
        }
        return false;
    }

    /**
     * ???????
     * @return ???
     */
    private String getSourceComment() {
        return commentMatcher.group();
    }

    /**
     * ?????????
     * @return ?????????? null
     */
    public Signature getSignature() {
        int commentEndPos = commentMatcher.end();
        String commentEndToEOF = source.substring(commentEndPos, source.length());
        // ??????????
        Matcher matcher = PatternCache.getPattern("(?s)/\\*(.*?)\\*/").matcher(commentEndToEOF);
        StringBuffer sb = new StringBuffer(commentEndToEOF.length());
        while (matcher.find()) {
            matcher.appendReplacement(sb, "/*");
            char[] cs = matcher.group(1).toCharArray();
            for (char c : cs) {
                switch (c) {
                case '*':
                case '\n':
                    sb.append(c);
                    break;
                default:
                    sb.append(' ');
                    break;
                }
            }
            sb.append("*/");
        }
        matcher.appendTail(sb);
        commentEndToEOF = sb.toString();

        // ???????????
        commentEndToEOF = FastStringUtils.replaceFirst(commentEndToEOF, "(?s)^(\\s*@[\\w]+\\s*\\(.*?\\))*\\s*", "");

        Pattern sigPattern = PatternCache.getPattern("(?s)(.+?)(throws|\\{|\\=|;|,\\s*/\\*|\\})");
        Matcher sigMatcher = sigPattern.matcher(commentEndToEOF);

        if (sigMatcher.find()) {

            // ?????
            ClassBlock classBlock = classStack.peek();
            while (commentEndPos > classBlock.end && classStack.size() > 1) {
                classStack.pop();
                classBlock = classStack.peek();
            }

            // ???Javadoc ?????
            // ?????????
            String sigStr = sigMatcher.group(1);
            sigStr = FastStringUtils.replaceFirst(sigStr, "(?s)/\\*[^\\*].*?\\*/\\s*", "");
            if (classKind.equals("@interface")) {
                sigStr = sigStr.replace("()", "");
            }
            Signature sig = new Signature(classBlock.name, sigStr);

            // ????
            if (sig.isDeclareInnerClass()) {
                String name = sig.getClassName();
                int end = searchEndOfInner(commentEndToEOF, name);
                classBlock = new ClassBlock(name, end);
                classStack.push(classBlock);
            }

            return sig;
        }

        log.warn("Javadoc ?????????????\n"
                + commentEndToEOF);
        return null;
    }

    public static String repeat(char ch, int repeat) {
        char[] buf = new char[repeat];
        for (int i = repeat - 1; i >= 0; i--) {
            buf[i] = ch;
        }
        return new String(buf);
    }

    /**
     * ??????
     * @param currentToEnd ???????
     * @param iClassName ??
     * @return ??
     */
    private int searchEndOfInner(String currentToEnd, String iClassName) {
        // ? { ???}?????????????
        // ????? java.util.Spliterators
        int nestLevel = 0;
        char[] c = currentToEnd.toCharArray();
        int last = c.length - 1;
        boolean startInnerClass = false;
        for (int i = 1; i <= last; i++) {
            if (c[i - 1] == '{') {
                nestLevel++;
                startInnerClass = true;
            } else if (c[i - 1] == '}') {
                nestLevel--;
            }
            if (startInnerClass == true && nestLevel == 0) {
                return commentMatcher.end() + i - 1;
            }
            if (c[i - 1] == '/' && c[i] == '*') {
                // ???
                for (i++; i <= last; i++) {
                    if (c[i - 1] == '*' && c[i] == '/') {
                        break;
                    }
                }
            } else if (c[i - 1] == '/' && c[i] == '/') {
                // ???
                for (i++; i <= last; i++) {
                    if (c[i] == '\n') {
                        i++;
                        break;
                    }
                }
            } else if (c[i - 1] != '\'' && c[i] == '"') {
                // ??????
                for (i++; i <= last; i++) {
                    if (c[i] == '"') {
                        if (c[i - 1] != '\\' || (c[i - 1] == '\\' && c[i - 2] == '\\')) {
                            break;
                        }
                    }
                }
            } else if (c[i - 1] != '"' && c[i] == '\'') {
                // ??????
                for (i++; i <= last; i++) {
                    if (c[i] == '\'') {
                        if (c[i - 1] != '\\' || (c[i - 1] == '\\' && c[i - 2] == '\\')) {
                            break;
                        }
                    }
                }
            }
        }

        log.warn(" " + className + "#" + iClassName
                + " ???????????");
        return -1;
    }

    /**
     * ????????
     * ??? null ??????
     * @param sig ??
     * @param comment ??
     */
    public void setLocalizedComment(Signature sig, Comment comment) {

        if (comment == null) {
            return;
        }
        String srcComment = getSourceComment();
        comment.setSourceBody(srcComment);
        String docComment = comment.buildComment();

        // debug setLocalizedComment ?????
        //log.debug("??: " + sig);
        //log.debug(" Java :\n" + srcComment);
        //log.debug(" API :\n" + docComment + "\n--------------");

        if (docComment == null || docComment.length() == 0) {
            return;
        }
        docComment = FastStringUtils.quoteReplacement(docComment);
        commentMatcher.appendReplacement(outputBuffer, docComment);
    }

    /**
     * ???? Java ????
     * @return ?? Java 
     */
    public String finishToString() {
        commentMatcher.appendTail(outputBuffer);
        String str = outputBuffer.toString();
        return str;
    }
}