alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 *
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 *
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.modules.javacore.jmiimpl.javamodel;

import java.util.ArrayList;
import org.netbeans.jmi.javamodel.BehavioralFeature;
import org.netbeans.jmi.javamodel.Element;
import org.netbeans.jmi.javamodel.JavaDoc;
import org.netbeans.jmi.javamodel.StatementBlock;
import org.netbeans.lib.java.parser.ASTree;
import org.netbeans.lib.java.parser.ParserTokens;
import org.netbeans.lib.java.parser.Token;
import org.netbeans.mdr.storagemodel.StorableObject;
import org.netbeans.modules.javacore.parser.*;
import javax.jmi.reflect.ConstraintViolationException;
import java.util.List;
import java.util.Stack;
import java.lang.ref.WeakReference;


/**
 *
 * @author  Martin Matula, Vladimir Hudec
 */
public abstract class BehavioralFeatureImpl extends FeatureImpl implements BehavioralFeature {
    protected String bodyText;
    private BodyReference body;
    protected boolean bodyInited = false;
    private StatementBlock hardBody;


    /** Creates a new instance of InitializerImpl */
    public BehavioralFeatureImpl(StorableObject s) {
        super(s);
    }

    /** The method has to make sure that the AST infos of children are also updated.
     */
    protected void matchElementInfo(ElementInfo newInfo) {
        super.matchElementInfo(newInfo);
        resetBody();
    }

    protected void uninitialize() {
        super.uninitialize();
        hardBody = null;
        retrieveBody();
    }

    protected void resetBody() {
        StatementBlock temp = retrieveBody();
        if (temp != null) {
            body = null;
            hardBody = null;
            changeChild(temp, null);
            temp.refDelete();
        }
        bodyInited = false;
    }

    protected void objectChanged(int mask) {
        super.objectChanged(mask);
        if ((mask | CHANGED_CHILDREN) == mask) {
            StatementBlock body = retrieveBody();
            if (body != null) {
                hardBody = body;
            }
        }
    }

    protected StatementBlock retrieveBody() {
        if (body == null) return null;
        StatementBlock result = (StatementBlock) body.get();
        return result;
    }

    protected abstract ASTree getBodyAST();

    public java.lang.String getBodyText() {
        if (isChanged(CHANGED_BODY)) {
            if (hardBody != null) {
                throw new ConstraintViolationException(null, null, "Cannot ask for body text after the body was changed."); // NOI18N
            }
            return bodyText;
        } else {
            ASTree body=getBodyAST();
            if (body.getType() == ParserTokens.SEMICOLON) {
                return null;
            } else {
                ASTProvider parser=getParser();
                if (parser==null)
                    return null;
                Token firstToken=parser.getToken(body.getFirstToken());
                Token lastToken=parser.getToken(body.getLastToken());

                // remove { } from body text
                 return parser.getSourceText().substring(firstToken.getEndOffset(),lastToken.getStartOffset());
            }
        }
    }

    public void setBodyText(java.lang.String newValue) {
        if (!childrenInited) {
            initChildren();
        }
        StatementBlock body = retrieveBody();
        if (bodyInited && body != null) {
            changeChild(body, null);
        }
        objectChanged(CHANGED_BODY);
        bodyInited = true;
        bodyText = newValue;
        body = null;
    }

    public StatementBlock getBody() {
        if (isChanged(CHANGED_BODY) && bodyText != null) {
            throw new ConstraintViolationException(null, null, "Cannot ask for body after the body text was changed."); // NOI18N
        }
        StatementBlock body = retrieveBody();
        if (!bodyInited) {
            body = initBody();
        }
        return body;
    }

    protected void resetChildren() {
        resetBody();
    }

    public StatementBlock initBody() {
        bodyInited = false;
        if (!childrenInited) {
            initChildren();
        }
        StatementBlock body = retrieveBody();
        FeatureInfo bodyTree = (FeatureInfo) getElementInfo();
        if (bodyTree != null) {
            ASTree bodyAST = getBodyAST();
            if (bodyAST.getType() == ParserTokens.SEMICOLON) {
                body = null;
            } else {
                bodyTree.doAttribution(this);
                body = (StatementBlock) initOrCreate(body, bodyAST);
            }
        }
        this.body = body == null ? null : new BodyReference(body);
        bodyInited = true;
        return body;
    }

    protected void setData(List annotations, String javadocText, JavaDoc javadoc, StatementBlock body, String bodyText) {
        super.setData(annotations, javadocText, javadoc);
        if (bodyText == null) {
            changeChild(null, body);
            this.hardBody = body;
            this.body = body == null ? null : new BodyReference(body);
        } else {
            if (body != null) {
                throw new ConstraintViolationException(null, null, "Cannot set both bodyText and body."); // NOI18N
            }
            this.bodyText = bodyText;
        }
        bodyInited = true;
    }

    public void setBody(StatementBlock newValue) {
        StatementBlock body = retrieveBody();
        if (!bodyInited) {
            body = initBody();
        }
        changeChild(body, newValue);
        hardBody = newValue;
        this.body = newValue == null ? null : new BodyReference(newValue);
        bodyText = null;
        objectChanged(CHANGED_BODY);
    }

    public List getChildren() {
        List list = super.getChildren();
        if (!isChanged(CHANGED_BODY) || bodyText == null) {
            addIfNotNull(list, getBody());
        }
        return list;
    }

    protected List getInitedChildren() {
        List list = new ArrayList(1);
        StatementBlock body = retrieveBody();
        if (bodyInited && (!isChanged(CHANGED_BODY) || bodyText == null)) {
            addIfNotNull(list, body);
        }
        return list;
    }

    public void replaceChild(Element oldElement, Element newElement) {
        StatementBlock body = retrieveBody();
        if (bodyInited && oldElement.equals(body)) {
            setBody((StatementBlock) newElement);
            return;
        }
        super.replaceChild(oldElement, newElement);
    }

    protected String indentBody(String oldBody) {
        StringBuffer sb = new StringBuffer();
        int state = 0;
        StringBuffer line = new StringBuffer();
        int level = 0;
        int raiseLevel = 0;
        int bracket = 0;
        boolean isStatement = false;
        boolean previousStatement = false;
        int questionMark = 0;
        Stack stack = new Stack();
        for (int i = 0; i < oldBody.length(); i++) {
            char ch = oldBody.charAt(i);
            if (ch == '\n') {
                if (i != 0)
                    sb.append(getBodyIndentation()).append(getInnerIndentation(level)).append(line).append(ch);
                else
                    sb.append(ch);
                line = new StringBuffer();
                if (state != 8) state = 0;
                level += raiseLevel;
                if (isStatement && !previousStatement) {
                    level++;
                } else if (!isStatement && previousStatement) {
                    level--;
                }
                previousStatement = isStatement;
                raiseLevel = 0;
            } else {
                switch (state) {
                    case 0:  // leading whitespaces
                        if (!Character.isWhitespace(ch)) {
                            state = 1;
                        } else {
                            break;
                        }
                    case 1:  // code
                        switch (ch) {
                            case '/':
                                state = 2;
                                break;
                            case '"':
                                state = 10;
                                isStatement = true;
                                break;
                            case '\'':
                                state = 4;
                                isStatement = true;
                                break;
                            case '{':
                                if (bracket == 0 && questionMark == 0) {
                                    if (!stack.isEmpty()) {
                                        stack.push("bracket"); // NOI18N
                                    }
                                    isStatement = false;
                                    raiseLevel++;
                                } else {
                                    isStatement = true;
                                }
                                break;
                            case '}':
                                if (bracket == 0 && questionMark == 0) {
                                    if (!stack.isEmpty()) {
                                        if ("colon".equals(stack.pop())) level--; // NOI18N
                                    }
                                    isStatement = false;
                                    if (line.length() == 0) {
                                        level--;
                                    } else {
                                        raiseLevel--;
                                    }
                                } else {
                                    isStatement = true;
                                }
                                break;
                            case ';':
                                if (bracket == 0) {
                                    isStatement = false;
                                } else {
                                    isStatement = true;
                                }
                                questionMark = 0;
                                break;
                            case '?':
                                questionMark++;
                                isStatement = true;
                                break;
                            case '(':
                                bracket++;
                                isStatement = true;
                                break;
                            case ')':
                                bracket--;
                                isStatement = true;
                                break;
                            case ':':
                                if (questionMark > 0) {
                                    questionMark--;
                                } else {
                                    if (!stack.isEmpty() && stack.peek().equals("colon")) { // NOI18N
                                        level--;
                                        raiseLevel++;
                                    } else {
                                        stack.push("colon"); // NOI18N
                                        raiseLevel++;
                                    }
                                    isStatement = false;
                                    break;
                                }
                                isStatement = true;
                                break;
                            default:
                                if (!Character.isWhitespace(ch)) {
                                    isStatement = true;
                                }
                                break;
                        }
                        if (ch != '\n') {
                            line.append(ch);
                        }
                        break;
                    case 2: // maybe a comment (/) - is it followed by another / or *?
                        if (ch == '/') {
                            state = 3;
                        } else if (ch == '*') {
                            state = 8;
                        } else {
                            isStatement = true;
                            state = 1;
                        }
                        line.append(ch);
                        break;
                    case 3: // simple comment
                        line.append(ch);
                        break;
                    case 8: // multi-line comment
                        if (ch == '*') {
                            state = 9;
                        }
                        line.append(ch);
                        break;
                    case 9: // end of comment?
                        if (ch == '/') {
                            state = 1;
                        } else if (ch != '*') {
                            state = 8;
                        }
                        line.append(ch);
                        break;
                    case 4: // char literal
                        if (ch == '\\') { // escape
                            state = 11;
                        } else if (ch == '\'') {
                            state = 1;
                        }
                        line.append(ch);
                        break;
                    case 11: // escape in char literal
                        state = 4;
                        line.append(ch);
                        break;
                    case 10: // string literal
                        if (ch == '\\') {
                            state = 12;
                        } else if (ch == '"') {
                            state = 1;
                        }
                        line.append(ch);
                        break;
                    case 12: // escape in string literal
                        state = 10;
                        line.append(ch);
                        break;
                }
            }
        }
        if (line.length()>0)
            sb.append(getBodyIndentation()).append(getInnerIndentation(level)).append(line).append('\n');
        return sb.toString();
    }

    /**
     * Generates body and appends it to the buffer provided as a parameter.
     * If the body was set as a text, it uses the bodyText field, otherwise
     * it generates it from the model elements.
     * (Considers StatementBlock as a root.)
     *
     * NOTE: Should be called only when the body was changed!
     *
     * @param  buf        buffer to append to
     */
    protected void generateBody(StringBuffer buf) {
        StatementBlock body = retrieveBody();
        if (!bodyInited) {
            body = initBody();
        }
        if (bodyText != null && bodyText.length() > 0 && !bodyText.equals("\n")) { // NOI18N
            formatElementPart(BODY_OPEN_CURLY, buf);
            buf.append(indentBody(bodyText));
            formatElementPart(BODY_CLOSE_CURLY, buf);
        } else if (body != null) {
            buf.append(((StatementBlockImpl) body).getSourceText());
        } else {
            formatElementPart(BODY_OPEN_CURLY, buf);
            formatElementPart(BODY_CLOSE_CURLY, buf);
        }
    }

    /**
     * Creates diff items for the body. When body text change, it adds
     * one diff item for the whole body. Otherwise it collects changes
     * from StatementBlock.
     *
     * todo (#pf): StatementBlock partial changes not implmeneted yet.
     *
     * @param  diffList  list of DiffElement, method adds new items to it
     */
    protected void createBodyDiffs(List diffList) {
        ASTProvider parser = getParser();
        if (hardBody == null) {// we have changed bodyText, not statement block
            if (isChanged(CHANGED_BODY)) {
                int startOffset;
                int endOffset;
                StringBuffer buf = new StringBuffer();
                if (bodyText == null) {
                    Token bodyStart = parser.getToken(getBodyAST().getFirstToken() - 1);
                    startOffset = bodyStart.getEndOffset();
                    buf.append(';');
                } else {
                    Token bodyStart = parser.getToken(getBodyAST().getFirstToken());
                    startOffset = bodyStart.getStartOffset();
                    formatElementPart(BODY_OPEN_CURLY, buf);
                    buf.append(indentBody(bodyText));
                    formatElementPart(BODY_CLOSE_CURLY, buf);
                }
                Token bodyEnd = parser.getToken(getBodyAST().getLastToken());
                endOffset = bodyEnd.getEndOffset();
                diffList.add(new DiffElement(startOffset, endOffset, buf.toString()));
            }
        } else { // statement block of body has been changed
            getChildDiff(diffList, parser, getBodyAST(), (MetadataElement) getBody(), CHANGED_BODY);
        }
    }

    private class BodyReference extends WeakReference {
        BodyReference(StatementBlock body) {
            super(body);
        }

        public Object get() {
            Object result = super.get();
            if (result==null) {
                body = null;
                bodyInited = false;
            }
            return result;
        }
    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.