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-2004 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.modules.javacore.jmiimpl.javamodel;

import org.netbeans.jmi.javamodel.*;
import org.netbeans.lib.java.parser.ASTree;
import org.netbeans.lib.java.parser.ASTreeTypes;
import org.netbeans.lib.java.parser.ParserTokens;
import org.netbeans.lib.java.parser.Token;
import org.netbeans.mdr.handlers.AttrListWrapper;
import org.netbeans.mdr.handlers.BaseObjectHandler;
import org.netbeans.mdr.handlers.InstanceHandler;
import org.netbeans.mdr.persistence.StorageException;
import org.netbeans.mdr.storagemodel.StorableFeatured;
import org.netbeans.mdr.storagemodel.StorableObject;
import org.netbeans.modules.javacore.ClassIndex;
import org.netbeans.modules.javacore.parser.*;
import org.netbeans.modules.javacore.JMManager;
import org.openide.ErrorManager;
import org.openide.text.PositionBounds;
import javax.jmi.reflect.InvalidObjectException;
import javax.jmi.reflect.RefClass;
import javax.jmi.reflect.RefFeatured;
import javax.jmi.reflect.RefObject;
import java.lang.ref.Reference;
import java.util.*;

/** Defines method for children initialization and changes management.
 *
 * @author  Martin Matula
 */
public abstract class MetadataElement extends InstanceHandler implements Element {
    public static final int CHANGED_CHILDREN = 1;
    public static final int CHANGED_NAME = 1 << 1;
    public static final int CHANGED_MODIFIERS = 1 << 2;
    public static final int CHANGED_IS_STATIC = CHANGED_MODIFIERS;
    public static final int CHANGED_IS_FINAL = CHANGED_MODIFIERS;
    public static final int CHANGED_IS_ON_DEMAND = 1 << 3;
    public static final int CHANGED_THROWS = CHANGED_IS_ON_DEMAND;
    public static final int CHANGED_JAVADOC = 1 << 4;
    public static final int CHANGED_BODY = 1 << 5;
    public static final int CHANGED_TYPE = 1 << 6;
    public static final int CHANGED_EXTENDS = CHANGED_THROWS;
    public static final int CHANGED_IMPLEMENTS = 1 << 7;
    public static final int CHANGED_INITIAL_VALUE = CHANGED_BODY;
    public static final int CHANGED_PARAMETERS = 1 << 8;
    public static final int CHANGED_PACKAGE_NAME = 1 << 9;
    public static final int CHANGED_FEATURES = CHANGED_PARAMETERS;
    public static final int CHANGED_CLASSIFIERS = CHANGED_FEATURES;
    public static final int CHANGED_IMPORTS = CHANGED_BODY;
    public static final int CHANGED_STATEMENTS = CHANGED_FEATURES;
    public static final int CHANGED_LABEL = CHANGED_NAME;
    public static final int CHANGED_THEN_PART = CHANGED_BODY;
    public static final int CHANGED_ELSE_PART = 1 << 10;
    public static final int CHANGED_EXPRESSION = 1 << 11;
    public static final int CHANGED_STEPS = CHANGED_FEATURES;
    public static final int CHANGED_INIT = CHANGED_THROWS;
    public static final int CHANGED_CASES = CHANGED_STEPS;
    public static final int CHANGED_VALUE = CHANGED_EXPRESSION;
    public static final int CHANGED_LOCK = CHANGED_EXPRESSION;
    public static final int CHANGED_DETAIL = CHANGED_BODY;
    public static final int CHANGED_FINALIZER = CHANGED_EXPRESSION;
    public static final int CHANGED_CATCHES = CHANGED_FEATURES;
    public static final int CHANGED_PARAMETER = CHANGED_EXPRESSION;
    public static final int CHANGED_RIGHT_SIDE = CHANGED_ELSE_PART;
    public static final int CHANGED_LEFT_SIDE = CHANGED_THEN_PART;
    public static final int CHANGED_OPERATOR = CHANGED_EXPRESSION;
    public static final int CHANGED_CONDITION = CHANGED_EXPRESSION;
    public static final int CHANGED_TRUE_PART = CHANGED_THEN_PART;
    public static final int CHANGED_FALSE_PART = CHANGED_ELSE_PART;
    public static final int CHANGED_ARRAY = CHANGED_LEFT_SIDE;
    public static final int CHANGED_INDEX = CHANGED_RIGHT_SIDE;
    public static final int CHANGED_PARENT_CLASS = CHANGED_EXPRESSION;
    public static final int CHANGED_ENCLOSING_CLASS = CHANGED_PARENT_CLASS;
    public static final int CHANGED_CLASS_DEFINITION = CHANGED_ELSE_PART;
    public static final int CHANGED_HAS_SUPER = CHANGED_MODIFIERS;
    public static final int CHANGED_ELEMENT_VALUES = CHANGED_FEATURES;
    public static final int CHANGED_DIMENSIONS = CHANGED_FEATURES;
    public static final int CHANGED_VARIABLES = CHANGED_FEATURES;
    public static final int CHANGED_TEXT = CHANGED_NAME;
    public static final int CHANGED_INITIALIZER = CHANGED_EXPRESSION;
    public static final int CHANGED_PARENT = CHANGED_EXPRESSION;
    public static final int CHANGED_CLASS_NAME = 1 << 12;
    public static final int CHANGED_DIM_COUNT = 1 << 13;
    public static final int CHANGED_ITERABLE = CHANGED_EXPRESSION;
    public static final int CHANGED_CONSTANTS = CHANGED_DIM_COUNT;
    public static final int CHANGED_IS_VARARG = CHANGED_BODY;
    public static final int CHANGED_TYPE_ARGUMENTS = 1 << 14;
    public static final int CHANGED_ANNOTATION = 1 << 15;
    public static final int CHANGED_BOUNDS = CHANGED_MODIFIERS;
    public static final int CHANGED_TYPE_PARAMETERS = 1 << 16;
    public static final int CHANGED_BOUND = CHANGED_BOUNDS;
    public static final int CHANGED_IS_LOWER = CHANGED_EXPRESSION;
    public static final int CHANGED_ARGUMENTS = CHANGED_STATEMENTS;
    public static final int CHANGED_ENUM_CONST_BODY = CHANGED_CLASS_DEFINITION;

    // value of this field will be lazily initialized from editor setting
    protected static String INDENTATION = "    "; // NOI18N
    /**
     * Contains information about spaces per tab character. In addition to,
     * it holds also information if the INDENTATION field is initialized from
     * editor setting. -1 means it is not initialized yet.
     */
    protected static int spacesPerTab = -1;
    
    private int changes = 0;
    private boolean isValid = true;
    protected boolean childrenInited = false;
    public boolean disableChanges = false;

    public MetadataElement(StorableObject o) {
        super(o);
    }

    protected final void initCheck() {
        if (!isValid()) {
            throw new InvalidObjectException(null, "Object was deleted."); // NOI18N
        }
        if (!isInitialized()) {
            if (this instanceof ResourceImpl) {
                ((ResourceImpl) this).initResource(null);
            } else {
                MetadataElement parent = (MetadataElement) refImmediateComposite();
                // the element must have a parent
                // with an exception of Resource
                if (parent != null)
                    parent.initChildren();
            }
        }
    }

    protected void _delete() {
        // --- delete from composite --------------------------------------
        MetadataElement parent = (MetadataElement) refImmediateComposite();
        if (parent != null) {
            parent.removeChild(this);
        }
        // --- delete children --------------------------------------------
//        for (Iterator it = getInitedChildren().iterator(); it.hasNext();) {
//            ((RefObject) it.next()).refDelete();
//        }
        // --- delete this instance ---------------------------------------
//        ((ExclusiveMutex) _getMdrStorage().getRepositoryMutex()).removeNew(this);
        isValid = false;
    }

    /** Part ot the rollback mechanism.
     *
     * In the case of any rollback, all classes should be rebuilt from ASTrees.
     * The layout for method is the next one:
     * protected void reset() {
     *   .. do your own job...
     *   super.reset()
     * }
     */
    protected void rollback() {
        if (isNew()) {
            isValid = false;
        } else {
            isValid = true;
            resetChange();
            boolean changes = disableChanges;
            disableChanges = true;
            try {
                //resetValues();
                for (Iterator it = getInitedChildren().iterator(); it.hasNext();) {
                    ((MetadataElement) it.next()).rollback();
                }
                resetChildren();
            } finally {
                disableChanges = changes;
            }
        }
    }

    protected final void commit() {
        //if (isNew()) {
            // the element is new => remove it from the registry
            //((ExclusiveMutex) _getMdrStorage().getRepositoryMutex()).removeNew(this);
        //}
        for (Iterator it = getInitedChildren().iterator(); it.hasNext();) {
            ((MetadataElement) it.next()).commit();
        }
        uninitialize();
    }

    protected abstract boolean isInitialized();
    protected abstract void uninitialize();

//    protected void resetValues() {
//    }

    public boolean isValid() {
        return isValid;
    }

    protected abstract Object getInternalForm();

    protected void initChildren() {
    }

    protected void resetChildren() {
    }

    protected List getInitedChildren() {
        if (childrenInited) {
            return getChildren();
        } else {
            return Collections.EMPTY_LIST;
        }
    }

    public List getChildren() {
        return Collections.EMPTY_LIST;
    }

    static void addIfNotNull(Collection collection, Object value) {
        if (value != null) {
            collection.add(value);
        }
    }

    protected void parentChanged() {
    }

    protected int getParentChangedMask(int mask) {
        return CHANGED_CHILDREN;
    }

    protected void objectChanged(int mask) {
        if (!isValid()) throw new InvalidObjectException(null, "Object was deleted."); // NOI18N
        if (disableChanges) return;
        if (!isChanged()) {
            if (!childrenInited) {
                // todo: this is only necessary for elements that have persistent children
                initChildren();
            }
            Object parent = refImmediateComposite();
            if (parent != null && parent instanceof MetadataElement) {
                ((MetadataElement) parent).objectChanged(getParentChangedMask(mask));
            }
        }
        changes |= mask;
    }

    /**
     * Returns source-code representation of the element in case of element
     * does not contain any change and is not newly added. In such cases
     * (when element is new or changed) it returns null.
     *
     * @return  null in case of newly added or changed element, otherwise
     *          source-code representation.
     */
    protected final String checkChange() {
        // there is not any change, return original element in case of element
        // is not new element
        if (!isNew()) {
            if (!isChanged()) {
                String origSrc = getParser().getSourceText();
                return origSrc.substring(getBeginIndex(), getEndIndex());
            } else {
                if (!childrenInited) {
                    initChildren();
                }
            }
        }
        return null;
    }

    protected final void resetChange() {
        if (disableChanges) return;
        changes = 0;
    }

    protected final void setChanged() {
        if (disableChanges) return;
        changes = ~0;
    }

    protected final void resetChange(int mask) {
        if (disableChanges) return;
        changes &= ~mask;
    }

    protected final boolean isChanged() {
        return changes != 0;
    }

    protected final boolean isChanged(int mask) {
        return (changes & mask) != 0;
    }

    /** Method used to create children list from the AST
     * @param currentList Current list of children that the method should update with new ASTs or rebuild (in not applicable, pass null)
     * @param attrName Name of MOF attribute that holds the list returned by this method.
     * @param tree AS tree that represents a child or children to be put into the returned list.
     * @param groupNodeType In case there can be one child or a group node of several children
     *      represented by tree parameter, this attribute contains type of node that corresponds
     *      to the group node (to determine whether there is a single child or a group of children under a group node.
     * @param changeMask Bit that should be set in change flags of owner of the returned list if the list changes.
     * @param rebuild Indicates whether this method should completely rebuild the existing list (if passed in the first
     *      parameter) or whether it is expected that the list contains the same element, only their AS trees should be updated (in case of false value).
     * @return List of children.
     */
    protected final LightAttrList createChildrenList(LightAttrList currentList, String attrName, ASTree tree, int groupNodeType, int changeMask, boolean rebuild) {
        return createChildrenList(currentList, attrName, getChildNodes(tree, groupNodeType), changeMask, rebuild);
    }

    /** Method used to create children list from the AST */
    protected final LightAttrList createChildrenList(LightAttrList currentList, String attrName, ASTree[] trees, int changeMask, boolean rebuild) {
        return createChildrenList(currentList, attrName, trees, 0, changeMask, rebuild);
    }

    protected final LightAttrList createChildrenList(LightAttrList currentList, String attrName, ASTree[] trees, int index, int changeMask, boolean rebuild) {
        DeferredAttrList deferredList;
        try {
            if (currentList != null && trees != null) {
                deferredList = (DeferredAttrList) ((AttrListWrapper) currentList.getInnerList()).getInnerList();
                if (rebuild) {
                    for (Iterator it = deferredList.iterator(); it.hasNext();) {
                        MetadataElement temp = (MetadataElement) it.next();
                        it.remove();
                        temp.refDelete();
                    }
                } else {
                    int i = index;
                    for (ListIterator it = deferredList.listIterator(); it.hasNext(); i++) {
                        TransientElement im = (TransientElement) it.next();
                        if (isNew()) {
                            im.setNew();
                        } else {
                            if (i >= trees.length) {
                                it.remove();
                            } else {
                                Element newElement = initOrCreate(im, trees[i]);
                                if (newElement != im) {
                                    it.set(newElement);
                                }
                            }
                        }
                    }
                    for (; i < trees.length; i++) {
                        deferredList.add(createElement(trees[i]));
                    }
                    deferredList = null;
                }
            } else {
                StorableFeatured storable = (StorableFeatured) _getDelegate();
                deferredList = new DeferredAttrList(storable, storable.getClassProxy().getAttrDesc(attrName), new ArrayList());
                currentList = createWrapper(attrName, deferredList, changeMask);
            }
            if (deferredList != null && trees != null) {
                for (int i = index; i < trees.length; i++) {
                    TransientElement s = createElement(trees[i]);
                    if (s != null) {
                        deferredList.add(s);
                    }
                }
            }
        } catch (StorageException e) {
            throw (GeneralException) ErrorManager.getDefault().annotate(new GeneralException(e.getMessage()), e);
        }
        return currentList;
    }

    /** Method used to create children list from a list provided into the statement constructor */
    protected final LightAttrList createChildrenList(String attrName, List elements, int changeMask) {
        DeferredAttrList deferredList;
        try {
            ArrayList innerList;
            if (elements != null) {
                innerList = new ArrayList(elements.size());
                for (Iterator it = elements.iterator(); it.hasNext();) {
                    MetadataElement element = (MetadataElement) it.next();
                    ((DeferredObject) element._getDelegate()).setComposite(_getDelegate(), null, null);
                    innerList.add(element);
                }
            } else {
                innerList = new ArrayList();
            }
            StorableFeatured storable = (StorableFeatured) _getDelegate();
            deferredList = new DeferredAttrList(storable, storable.getClassProxy().getAttrDesc(attrName), innerList);
        } catch (StorageException e) {
            throw (GeneralException) ErrorManager.getDefault().annotate(new GeneralException(e.getMessage()), e);
        }
        return createWrapper(attrName, deferredList, changeMask);
    }

    protected final LightAttrList createWrapper(String attrName, List innerList, int changeMask) {
        AttrListWrapper list = new AttrListWrapper(this, innerList);
        list.setAttrName(attrName);
        return new LightAttrList(list, this, changeMask);
    }

    protected final void deleteChild(Element child) {
        if (child != null) {
            changeChild(child, null);
            child.refDelete();
        }
    }

    protected static void deleteChildren(Collection children) {
        for (Iterator it = children.iterator(); it.hasNext();) {
            RefObject element = (RefObject) it.next();
            it.remove();
            element.refDelete();
        }
    }

    protected final void changeChild(Element oldChild, Element newChild) {
        try {
            if (oldChild != null) {
                ((StorableObject) ((BaseObjectHandler) oldChild)._getDelegate()).clearComposite();
            }
            if (newChild != null) {
                ((StorableObject) ((BaseObjectHandler) newChild)._getDelegate()).setComposite(_getDelegate(), null, null);
            }
        } catch (StorageException e) {
            throw (GeneralException) ErrorManager.getDefault().annotate(new GeneralException(e.getMessage()), e);
        }
    }

    protected final TransientElement createElement(ASTree tree, RefClass proxy) {
        if (tree == null || proxy == null) return null;
        Object o = ((MEFactory) proxy).create(this);
        TransientElement result = (TransientElement) o;
        result.init(tree);
        return result;
    }

    public abstract MDRParser getParser();

    public ASTree getASTree() {
        return getASTree(getInternalForm());
    }

    public PositionBounds getPosition() {
        testResourceChange();
        PositionBounds result = null;
        ASTree tree = getASTree();
        if (tree != null) {
            result = ((MDRParser) tree.getASTContext()).createBounds(tree);
        }
        return result;
    }

    public final PositionBounds getPartPosition(ElementPartKind part, int position) {
        testResourceChange();
        return getParser().createBounds(getPartStartTree(part), getPartEndTree(part));
    }

    public Resource getResource() {
        RefObject parent = this;

        while (!(parent == null || parent instanceof Resource)) {
            parent = (RefObject) parent.refImmediateComposite();
        }
        return (Resource) parent;
    }

    protected final TransientElement createElement(ASTree tree) {
        if (tree == null) return null;
        return createElement(tree, getElementProxy(tree));
    }

    private RefClass getElementProxy(ASTree tree) {
        JavaModelPackage pkg = (JavaModelPackage) refImmediatePackage();
        int type = tree.getType();
        switch (type) {
            case ASTreeTypes.EXPLICIT_CONSTRUCTOR_INVOCATION:
                return pkg.getConstructorInvocation();
            case ASTreeTypes.ARRAY_INITIALIZER:
                return pkg.getArrayInitialization();
            case ASTreeTypes.ARRAY_CREATION_EXPRESSION:
                return pkg.getNewArrayExpression();
            case ASTreeTypes.LOCAL_VARIABLE_DECLARATION:
                return pkg.getLocalVarDeclaration();
            case ASTreeTypes.VARIABLE_DECLARATOR:
                return pkg.getLocalVariable();
            case ASTreeTypes.LABELED_STATEMENT:
                return pkg.getLabeledStatement();
            case ASTreeTypes.IF_STATEMENT:
                return pkg.getIfStatement();
            case ASTreeTypes.WHILE_STATEMENT:
                return pkg.getWhileStatement();
            case ASTreeTypes.FOR_STATEMENT:
                return pkg.getForStatement();
            case ASTreeTypes.FOR_EACH_STATEMENT:
                return pkg.getForEachStatement();
            case ASTreeTypes.BLOCK_STATEMENTS:
                return pkg.getStatementBlock();
            case ASTreeTypes.EXPRESSION_STATEMENT:
                return pkg.getExpressionStatement();
            case ASTreeTypes.EMPTY_STATEMENT:
                return pkg.getEmptyStatement();
            case ASTreeTypes.ASSIGNMENT:
                return pkg.getAssignment();
            case ASTreeTypes.INFIX_EXPRESSION:
                return pkg.getInfixExpression();
            case ASTreeTypes.PREFIX_EXPRESSION:
                return pkg.getPrefixExpression();
            case ASTreeTypes.POSTFIX_EXPRESSION:
                return pkg.getPostfixExpression();
            case ASTreeTypes.METHOD_INVOCATION:
                return pkg.getMethodInvocation();
            case ASTreeTypes.CLASS_INSTANCE_CREATION_EXPRESSION:
                return pkg.getNewClassExpression();
            case ASTreeTypes.COMPLEX_EXPRESSION:
                return pkg.getComplexExpression();
            case ASTreeTypes.CONDITIONAL_EXPRESSION:
                return pkg.getConditionalExpression();
            case ASTreeTypes.CAST_EXPRESSION:
                return pkg.getTypeCast();
            case ASTreeTypes.SWITCH_STATEMENT:
                return pkg.getSwitchStatement();
            case ASTreeTypes.SWITCH_LABEL:
            case ASTreeTypes.SWITCH_BLOCK_STATEMENT_GROUP:
                return pkg.getCase();
            case ASTreeTypes.DO_STATEMENT:
                return pkg.getDoStatement();
            case ASTreeTypes.BREAK_STATEMENT:
                return pkg.getBreakStatement();
            case ASTreeTypes.CONTINUE_STATEMENT:
                return pkg.getContinueStatement();
            case ASTreeTypes.RETURN_STATEMENT:
                return pkg.getReturnStatement();
            case ASTreeTypes.SYNCHRONIZE_STATEMENT:
                return pkg.getSynchronizedStatement();
            case ASTreeTypes.THROW_STATEMENT:
                return pkg.getThrowStatement();
            case ASTreeTypes.TRY_STATEMENT:
                return pkg.getTryStatement();
            case ASTreeTypes.CATCH_CLAUSE:
                return pkg.getCatch();
            case ASTreeTypes.ASSERT_STATEMENT:
                return pkg.getAssertStatement();
            case ASTreeTypes.REFERENCE_TYPE:
                return pkg.getArrayReference();
            case ASTreeTypes.MULTI_PART_ID:
            case ParserTokens.IDENTIFIER:
                if (getParser().isVariableAccess(tree)) {
                    return pkg.getVariableAccess();
                }
            case ASTreeTypes.PRIMITIVE_TYPE:
                return pkg.getMultipartId();
            case ASTreeTypes.FIELD_DECLARATION:
            case ASTreeTypes.METHOD_DECLARATION:
            case ASTreeTypes.CLASS_DECLARATION:
            case ASTreeTypes.INTERFACE_DECLARATION:
            case ASTreeTypes.INSTANCE_INITIALIZER:
            case ASTreeTypes.STATIC_INITIALIZER:
            case ASTreeTypes.CONSTRUCTOR_DECLARATION:
            case ASTreeTypes.CLASS_BODY_DECLARATIONS:
                //return pkg.getClassDefinition();
                // temporary -- ignore local classes
                return null;
            case ASTreeTypes.PRIMARY_CLASS:
                return pkg.getClassExpression();
            case ASTreeTypes.PRIMARY_THIS:
                return pkg.getThisExpression();
            case ASTreeTypes.FIELD_ACCESS:
                return pkg.getVariableAccess();
            case ASTreeTypes.ARRAY_ACCESS:
                return pkg.getArrayAccess();
            case ParserTokens.INT_LIT:
                if (((Token) tree).getValue() instanceof Long) {
                    return pkg.getLongLiteral();
                } else {
                    return pkg.getIntLiteral();
                }
            case ParserTokens.FLOAT_LIT:
                if (((Token) tree).getValue() instanceof Float) {
                    return pkg.getFloatLiteral();
                } else {
                    return pkg.getDoubleLiteral();
                }
            case ParserTokens.BOOL_LIT:
                return pkg.getBooleanLiteral();
            case ParserTokens.CHAR_LIT:
                return pkg.getCharLiteral();
            case ParserTokens.STRING_LIT:
                return pkg.getStringLiteral();
            case ParserTokens.NULL_LIT:
                return pkg.getNullLiteral();
            case ASTreeTypes.SUPER_:
                return pkg.getMultipartId();
            case ASTreeTypes.WILDCARD:
                return pkg.getWildCard();
            case ASTreeTypes.ARGUMENT_LIST:
                return pkg.getArgumentList();
            case ASTreeTypes.ELEMENT_VALUE_PAIR:
                return pkg.getAttributeValue();
            case ASTreeTypes.ERRONEOUS:
                return null;
            default:
                throw new RuntimeException("Unexpected type of ASTree: " + type); // NOI18N
        }
    }

    /**
     * Used for obtaining source-code representation of the element. This
     * method is called by parent when the element is newly added or we need
     * to regenerate whole element.
     *
     * @return  source-code representation of element
     */
    public String getSourceText() {
        return "";
    }

    /**
     * Used for obtaining changes and put them to the list.
     *
     * @param  diffList  list, where the changes are put by method. Contains
     *                   DiffElement instances.
     */
    public void getDiff(List diffList) {
    }

    protected abstract void setNew();
    protected abstract boolean isNew();

    public final void replaceNode(List diff, ASTProvider parser, ASTree node, String text, int start, String prefix) {
        int startOffset;
        int endOffset;
        if ((text == null && prefix != null) || node == null) {
            startOffset = start;
        } else {
            startOffset = getStartOffset(parser, node, false);
        }
        if (node == null) {
            endOffset = startOffset;
            if (text != null && prefix != null) {
                text = prefix + text;
            }
        } else {
            endOffset = parser.getToken(node.getLastToken()).getEndOffset();
        }
        if (text == null) {
            text = "";
        }
        diff.add(new DiffElement(startOffset, endOffset, text));
    }

    protected final void getChildDiff(List diff, ASTProvider parser, ASTree node, MetadataElement child, int changeMask) {
        getChildDiff(diff, parser, node, child, changeMask, 0, null);
    }

    protected final void getChildDiff(List diff, ASTProvider parser, ASTree node, MetadataElement child, int changeMask, int startOffset, String prefix) {
        if (isChanged(changeMask)) {
            replaceNode(diff, parser, node, child == null ? null : child.getSourceText(), startOffset, prefix);
        } else if (child != null && child.isChanged()) {
            child.getDiff(diff);
        }
    }

    public final void getElementsDiff(List diff, Collection newElements) {
        for (Iterator it = newElements.iterator(); it.hasNext();) {
            MetadataElement me = (MetadataElement) it.next();
            if (me.isChanged())
                me.getDiff(diff);
        }
    }
    public final void getCollectionDiff(List diff, ASTProvider parser, int changeMask, Object[] oldElements, Collection newElements, int endOffset, String separator) {
        getCollectionDiff(diff, parser, changeMask, oldElements, newElements, endOffset, separator, true);
    }

    public final void getCollectionDiff(List diff, ASTProvider parser, int changeMask, Object[] oldElements, Collection newElements, int endOffset, String separator, boolean includePadds) {
        if (isChanged(changeMask)) {
            getCollectionDiff(diff, parser, oldElements, newElements, endOffset, separator, null, 0, includePadds);
        } else if (isChanged(CHANGED_CHILDREN)) {
            getElementsDiff(diff, newElements);
        }
    }

    public final void getCollectionDiff(List diff, ASTProvider parser, int changeMask, ASTree oldParentNode, Collection newElements, int startOffset, String separator, String prefixIfNew) {
        getCollectionDiff(diff, parser, changeMask, oldParentNode, oldParentNode == null ? 0 : oldParentNode.getType(), newElements, startOffset, separator, prefixIfNew);
    }

    public final void getCollectionDiff(List diff, ASTProvider parser, int changeMask, ASTree oldParentNode, int groupNodeType, Collection newElements, int startOffset, String separator, String prefixIfNew) {
        if (isChanged(changeMask)) {
            ASTree[] oldASTs;
            int endOffset;
            if (oldParentNode == null) {
                endOffset = startOffset;
                oldASTs = new ASTree[0];
            } else {
                if (oldParentNode.getType() == groupNodeType) {
                    oldASTs = oldParentNode.getSubTrees();
                } else {
                    oldASTs = new ASTree[] {oldParentNode};
                }
                if (oldASTs.length == 0) {
                    endOffset = startOffset;
                } else {
                    endOffset = parser.getToken(oldASTs[oldASTs.length - 1].getLastToken()).getEndOffset();
                }
            }
            getCollectionDiff(diff, parser, oldASTs, newElements, endOffset, separator, prefixIfNew, startOffset, true);
        } else if (isChanged(CHANGED_CHILDREN)) {
            getElementsDiff(diff, newElements);
        }
    }

    private void getCollectionDiff(List diff, ASTProvider parser, Object[] oldElements, Collection newElements, int endOffset, String separator, String prefixIfNew, int startOffset, boolean includePadds) {
        //MethodInfo astInfo = (MethodInfo) getElementInfo();
        if (newElements.isEmpty()) {
            if (oldElements.length > 0 && prefixIfNew != null) {
                diff.add(new DiffElement(startOffset, endOffset, ""));
                return;
            }
        }
        CollectionMatcher matcher = new CollectionMatcher(oldElements, newElements);
        int newPos = 0;
        int oldPos = 0;
        boolean isFirst = true;
        StringBuffer diffText = null;
        int positions[] = matcher.getPositions();
        Set deleted = matcher.getDeleted();
        int lastOffset = getOffset(0, parser, oldElements, endOffset, includePadds);
        ASTree lastElement = null;
        for (Iterator it = newElements.iterator(); it.hasNext(); newPos++) {
            boolean shouldDelete = false;
            int newLastOffset = 0;
            while (oldPos < oldElements.length && deleted.remove(oldElements[oldPos])) {
                shouldDelete = true;
                oldPos++;
                newLastOffset = getOffset(oldPos, parser, oldElements, endOffset, true);
                if (lastElement != null && oldPos == oldElements.length) {
                    lastOffset = parser.getToken(lastElement.getLastToken() + 1).getStartOffset();
                }
            }
            if (shouldDelete) {
                diff.add(new DiffElement(lastOffset, newLastOffset, ""));
                lastOffset = newLastOffset;
            }
            MetadataElement e = (MetadataElement) it.next();
            if (positions[newPos] != oldPos) {
                if (diffText == null) {
                    if (prefixIfNew == null || oldElements.length > 0) {
                        if (oldPos >= oldElements.length && !isFirst) {
                            diffText = new StringBuffer(separator);
                        } else {
                            diffText = new StringBuffer();
                        }
                    } else {
                        diffText = new StringBuffer(prefixIfNew);
                    }
                } else {
                    diffText.append(separator);
                }
                diffText.append(e.getSourceText());
                if (positions[newPos] != -1) {
                    deleted.add(oldElements[positions[newPos]]);
                }
            } else {
                if (diffText != null) {
                    diffText.append(separator);
                    newLastOffset = lastOffset;
                    if (e.isChanged()) {
                        diffText.append(e.getSourceText());
                        newLastOffset = e.getEndIndex();
                    }
                    diff.add(new DiffElement(lastOffset, newLastOffset, diffText.toString()));
                    diffText = null;
                } else {
                    if (e.isChanged()) {
                        e.getDiff(diff);
                    }
                }
                lastElement = getLastElement(oldPos, oldElements);
                oldPos++;
                lastOffset = getOffset(oldPos, parser, oldElements, endOffset, true);
                isFirst = false;
            }
        }
        if (oldPos < oldElements.length) {
            int newLastOffset = getOffset(oldElements.length, parser, oldElements, endOffset, true);
            if (lastElement != null) {
                lastOffset = getStartOffset(parser, parser.getToken(lastElement.getLastToken() + 1), true);
            }
            diff.add(new DiffElement(lastOffset, newLastOffset, diffText == null ? "" : diffText.toString()));
        } else if (diffText != null) {
            diff.add(new DiffElement(lastOffset, lastOffset, diffText.toString()));
        }
    }

    private int getOffset(int index, ASTProvider parser, Object[] oldElements, int endOffset, boolean includePadds) {
        if (oldElements.length <= index) {
            return endOffset;
        } else {
            return getStartOffset(parser, getChildASTree(oldElements[index]), includePadds);
        }
    }

    protected static int getStartOffset(ASTProvider parser, ASTree tree, boolean includePaddings) {
        Token startToken = parser.getToken(tree.getFirstToken());
        if (includePaddings) {
            Token[] pad = startToken.getPadding();
            if (pad.length > 0) {
                startToken = pad[0];
                for (int i = 0; i < pad.length; i++) {
                    if (pad[i].getType() == ParserTokens.EOL) {
                        String value = parser.getText(pad[i]);
                        return pad[i].getStartOffset() + value.indexOf('\n') + 1;
                    }
                }
            }
        }
        return startToken.getStartOffset();
    }

    void testResourceChange() {
        if (((ResourceImpl) getResource()).isChanged()) {
            throw new IllegalStateException("The model was modified. Unable to return start offset."); // NOI18N
        }
    }

    /**
     * Return the index of the first character of the elment.
     * todo (#pf): now, it is index of the first character after the element
     * before! (whitespaces and line ends should be divided between elements!
     * @return  index, where element starts
     */
    protected int getBeginIndex() {
        return getStartOffset(getParser(), getASTree(), true);
    }

    /**
     * Returns the start offset of the element in the original source text.
     *
     * @throws IllegalStateException  when element was changed
     * @return  start offset of the element
     */
    public int getStartOffset() {
        testResourceChange();
        return getStartOffset(getParser(), getASTree(), false);
    }

    /**
     * Start offset of part of the element.
     *
     * @param  part      identifies part of the element, see constants
     * @return   start offset of given part and position
     */
    public int getPartStartOffset(ElementPartKind part) {
        testResourceChange();
        return getParser().getToken(getPartStartTree(part).getFirstToken()).getStartOffset();
    }

    /**
     * Returns the end offset of the element in the original source text.
     *
     * @return  end offset of the element
     */
    public int getEndOffset() {
        testResourceChange();
        return getEndIndex();
    }

    /**
     * End offset of part of the element.
     *
     * @param  part      identifier part of the element, see constants
     * @return  end offset of given part and position
     */
    public int getPartEndOffset(ElementPartKind part) {
        testResourceChange();
        return getParser().getToken(getPartEndTree(part).getLastToken()).getEndOffset();
    }

    protected ASTree getPartStartTree(ElementPartKind part) {
        return getPartTree(part);
    }

    protected ASTree getPartEndTree(ElementPartKind part) {
        return getPartTree(part);
    }

    protected ASTree getPartTree(ElementPartKind part) {
        throw new IllegalArgumentException("Invalid part for this element: " + part.toString()); // NOI18N
    }

    /**
     * Return the index of the last character of the element. For example,
     * it is closing curly bracket of the method or semicolon at the end
     * of the field.
     *
     * @return  index, where element ends
     */
    protected int getEndIndex() {
        return getEndOffset(getParser(), getASTree());
    }

    protected static int getEndOffset(ASTProvider parser, ASTree tree) {
        Token endIndex = parser.getToken(tree.getLastToken());
        return endIndex.getEndOffset();
    }

    private ASTree getASTree(Object o) {
        if (o instanceof ElementInfo) {
            ElementInfo info = (ElementInfo) o;
            Reference sr = info.getASTree();
            if (sr == null) return null;

            ASTree result = (ASTree) sr.get();
            if (result == null) {
                result = info.refreshASTree();
            }
            return result;
        } else if (o instanceof ASTree) {
            return (ASTree) o;
        } else {
            return null;
        }
    }

    private ASTree getChildASTree(Object o) {
        return getASTree(o);
    }

    private ASTree getLastElement(int index, Object[] oldElements) {
        if (oldElements.length <= index) {
            return null;
        }
        return getChildASTree(oldElements[index]);
    }

    protected final Element initOrCreate(Element element, ASTree tree) {
        boolean changes = disableChanges;
        disableChanges = true;
        try {
            if (element != null) {
                if (tree != null) {
                    RefClass proxy = getElementProxy(tree);
                    if (element.refClass().equals(proxy)) {
                        ((TransientElement) element).init(tree);
                        return element;
                    }
                }
                ((TransientElement) element).invalidate();
            }
            return createElement(tree);
        } finally {
            disableChanges = changes;
        }
    }

    public final boolean isTransient() {
        return _getDelegate() instanceof DeferredObject;
    }
    
    public final boolean checkElementType(ElementInfo astInfo, Element element) {
        switch (astInfo.infoType) {
            case FieldInfo.FIELD_TYPE:
                return (element instanceof Field) && !(element instanceof EnumConstant);
            case FieldGroupInfo.FIELDGROUP_TYPE:
                return element instanceof FieldGroup;
            case EnumInfo.ENUM_TYPE:
                return element instanceof JavaEnum;
            case ClassInfo.INTERFACE_TYPE:
            case ClassInfo.CLASS_TYPE:
                return (element instanceof JavaClass) && !(element instanceof AnnotationType) && !(element instanceof JavaEnum);
            case AnnotationTypeInfo.ANNOTATIONTYPE_TYPE:
                return element instanceof AnnotationType;
            case ClassInfo.ANON_CLASS_TYPE:
                return (element instanceof ClassDefinition) && !(element instanceof JavaClass);
            case MethodInfo.METHOD_TYPE:
                return element instanceof Method;
            case FeatureInfo.INSTANCE_INITIALIZER_TYPE:
            case FeatureInfo.STATIC_INITIALIZER_TYPE:
                return element instanceof Initializer;
            case MethodInfo.CONSTRUCTOR_TYPE:
                return element instanceof Constructor;
            case ElementInfo.IMPORT_ON_DEMAND_TYPE:
            case ElementInfo.SINGLE_IMPORT_TYPE:
                return element instanceof Import;
            case ParameterInfo.PARAMETER_TYPE:
                return element instanceof Parameter;
            case TypeParamInfo.TYPEPARAM_TYPE:
                return element instanceof TypeParameter;
            case FeatureInfo.ENUM_CONSTANT_TYPE:
                return element instanceof EnumConstant;
            case AttributeInfo.ATTRIBUTE_TYPE:
                return element instanceof Attribute;
            case AnnotationInfo.ANNOTATION_TYPE:
                return element instanceof Annotation;
            default:
                throw new IllegalArgumentException("Illegal type "+astInfo.infoType); // NOI18N
        }
    }
    
    public final SemiPersistentElement createElement(ElementInfo astInfo) {
        return createElement(astInfo, true);
    }

    protected final SemiPersistentElement createElement(ElementInfo astInfo, boolean initialize) {
        if (astInfo == null) return null;
        JavaModelPackage extent = (JavaModelPackage) refImmediatePackage();
        SemiPersistentElement element=null;
        boolean isTransient = isTransient();
        
        switch (astInfo.infoType) {
            case FieldInfo.FIELD_TYPE: {
                FieldInfo info = (FieldInfo) astInfo;
                element = ((FieldClassImpl) extent.getField()).create(info.name, info.modifiers, info.type, isTransient);
                break;
            } case FieldGroupInfo.FIELDGROUP_TYPE: {
                FieldGroupInfo info = (FieldGroupInfo) astInfo;
                element = ((FieldGroupClassImpl) extent.getFieldGroup()).create(info.modifiers, info.type, isTransient);
                break;
            } case EnumInfo.ENUM_TYPE:
                if (isTransient) {
                    element = ((JavaEnumClassImpl) extent.getJavaEnum()).create(astInfo.name, ((EnumInfo) astInfo).modifiers, true);
                } else {
                    ClassIndex index=ClassIndex.getIndex(extent);

                    Set classes = index.getClassesByFqn(astInfo.name);
                    for (Iterator it = classes.iterator(); it.hasNext();) {
                        JavaClassImpl temp = (JavaClassImpl) it.next();
                        Object composite = temp.refImmediateComposite();
                        if (composite == null || this.equals(composite)) {
                            element = temp;
                            break;
                        }
                    }
                    if (element == null) {
                        element = recoverFromCNFII(astInfo, extent.getJavaEnum());
                    }
                }
                break;
            case ClassInfo.INTERFACE_TYPE:
            case ClassInfo.CLASS_TYPE:
                if (isTransient) {
                    ClassInfo info = (ClassInfo) astInfo;
                    element = ((JavaClassClassImpl) extent.getJavaClass()).create(astInfo.name, info.modifiers, info.superclass, info.interfaces, true);
                } else {
                    ClassIndex index=ClassIndex.getIndex(extent);

                    Set classes = index.getClassesByFqn(astInfo.name);
                    for (Iterator it = classes.iterator(); it.hasNext();) {
                        JavaClassImpl temp = (JavaClassImpl) it.next();
                        Object composite = temp.refImmediateComposite();
                        if (composite == null || this.equals(composite)) {
                            element = temp;
                            break;
                        }
                    }
                    if (element == null) {
                        element = recoverFromCNFII(astInfo, extent.getJavaClass());
                    }
                }
                break;
            case AnnotationTypeInfo.ANNOTATIONTYPE_TYPE:
                if (isTransient) {
                    element = ((AnnotationTypeClassImpl) extent.getAnnotationType()).create(astInfo.name, ((ClassInfo) astInfo).modifiers, true);
                } else {
                    ClassIndex index=ClassIndex.getIndex(extent);

                    Set classes = index.getClassesByFqn(astInfo.name);
                    for (Iterator it = classes.iterator(); it.hasNext();) {
                        JavaClassImpl temp = (JavaClassImpl) it.next();
                        Object composite = temp.refImmediateComposite();
                        if (composite == null || this.equals(composite)) {
                            element = temp;
                            break;
                        }
                    }
                    if (element == null) {
                        element = recoverFromCNFII(astInfo, extent.getAnnotationType());
                    }
                }
                break;            
            case ClassInfo.ANON_CLASS_TYPE:
                element = ((ClassDefinitionClassImpl) extent.getClassDefinition()).create();
                break;
            case MethodInfo.METHOD_TYPE: {
                MethodInfo info = (MethodInfo) astInfo;
                element = ((MethodClassImpl) extent.getMethod()).create(info.name, info.modifiers, info.type, info.exceptions, isTransient);
                break;
            } case FeatureInfo.INSTANCE_INITIALIZER_TYPE:
            case FeatureInfo.STATIC_INITIALIZER_TYPE:
                element = ((InitializerClassImpl) extent.getInitializer()).create(((FeatureInfo) astInfo).modifiers, isTransient);
                break;
            case MethodInfo.CONSTRUCTOR_TYPE: {
                MethodInfo info = (MethodInfo) astInfo;
                element = ((ConstructorClassImpl) extent.getConstructor()).create(info.modifiers, info.exceptions, isTransient);
                break;
            } case ElementInfo.IMPORT_ON_DEMAND_TYPE:
            case ElementInfo.SINGLE_IMPORT_TYPE:
                element = ((ImportClassImpl)extent.getImport()).create(astInfo.name, null, false, astInfo.infoType == ElementInfo.IMPORT_ON_DEMAND_TYPE, (ResourceImpl)this);
                break;
            case ParameterInfo.PARAMETER_TYPE: {
                ParameterInfo info = (ParameterInfo) astInfo;
                element = ((ParameterClassImpl) extent.getParameter()).create(info.name, info.isFinal, info.isVarArg, info.type, isTransient);
                break;
            } case TypeParamInfo.TYPEPARAM_TYPE: {
                TypeParamInfo info = (TypeParamInfo) astInfo;
                element = ((TypeParameterClassImpl) extent.getTypeParameter()).create(info.name, info.bounds, isTransient);
                break;
            } case FeatureInfo.ENUM_CONSTANT_TYPE:
                element = ((EnumConstantClassImpl) extent.getEnumConstant()).create(astInfo.name, isTransient);
                break;
            case AttributeInfo.ATTRIBUTE_TYPE:
                element = ((AttributeClassImpl) extent.getAttribute()).create(astInfo.name, ((AttributeInfo) astInfo).modifiers, ((AttributeInfo) astInfo).type, isTransient);
                break;
            case AnnotationInfo.ANNOTATION_TYPE:
                element = ((AnnotationClassImpl) extent.getAnnotation()).createAnn(astInfo.name, null);
                break;
            default:
                throw new IllegalArgumentException("Illegal type "+astInfo.infoType); // NOI18N
        }
        element.updatePersistent(astInfo);
        if (initialize) {
            element.setElementInfo(astInfo);
        }
        return element;
    }
    
    private static SemiPersistentElement recoverFromCNFII(ElementInfo info, RefClass classProxy) {
        JMManager.getLog().notify(ErrorManager.INFORMATIONAL, new Exception("Class not found in index: " + info.name + ". Recovering..."));
        if (classProxy instanceof JavaEnumClassImpl) {
            return ((JavaEnumClassImpl) classProxy).create(info.name, ((EnumInfo) info).modifiers, false);
        } else if (classProxy instanceof AnnotationTypeClassImpl) {
            return ((AnnotationTypeClassImpl) classProxy).create(info.name, ((ClassInfo) info).modifiers, false);
        } else {
            return ((JavaClassClassImpl) classProxy).create(info.name, ((ClassInfo) info).modifiers, ((ClassInfo) info).superclass, ((ClassInfo) info).interfaces, false);
        }
    }

    public static ASTree[] getChildNodes(ASTree parent, int groupNodeType) {
        if (parent == null) {
            return new ASTree[0];
        } else if (parent.getType() == groupNodeType) {
            return parent.getSubTrees();
        } else {
            return new ASTree[] {parent};
        }
    }
    
    public Type resolveType(TypeRef typeRef) {
        MetadataElement parent=(MetadataElement)refImmediateComposite();
        
        return parent.resolveType(typeRef);
    }

    /**
     * Returns indentation of the element. Every element, which should be
     * indented has to override this method.
     *
     * @return indentation for element.
     */
    protected String getIndentation() {
        if (spacesPerTab == -1) {
            JMManager.initIndentation();
        }
        return "";
    }

    // temporary part - should be read from options
    static String[][] data = null;
    static String[] EMPTY = { null, null, null };
    static {
        //
        data = new String[][] {
            EMPTY,                     //  0 EMPTY
            { "s", "{", "n" },         //  1 BODY_OPEN_CURLY // NOI18N
            { "i", "}", "" },          //  2 BODY_CLOSE_CURLY // NOI18N
            { "", "(", "" },           //  3 PAR_OPEN_BRACKET // NOI18N
            { "", ")", "" },           //  4 PAR_CLOSE_BRACKET // NOI18N
            { "", ",", "s" },          //  5 COMMA // NOI18N
            { null, null, null },      //  6 CALLABLE_IDENTIFIER
            { "s" , "throws", "s" },   //  7 THROWS_KEYWORD // NOI18N
            { "s", "=", "s" },         //  8 FIELD_EQUALS // NOI18N
            { "s", "extends", "s" },   //  9 EXTENDS_KEYWORD // NOI18N
            { "s", "implements", "s" },// 10 IMPLEMENTS_KEYWORD // NOI18N
            { "s", "{", "n" },         // 11 CLASS_OPEN_CURLY // NOI18N
            { "i", "}", "n" },         // 12 CLASS_CLOSE_CURLY // NOI18N
            { "", "[", "" },           // 13 ARRAY_OPEN_BRACKET // NOI18N
            { "", "]", "" },           // 14 ARRAY_CLOSE_BRACKET // NOI18N
            { "", "{", "" },           // 15 ARRAY_OPEN_CURLY // NOI18N
            { "", "}", "" },           // 16 ARRAY_CLOSE_CURLY // NOI18N
            { "i", "assert", "s" },    // 17 ASSERT_KEYWORD // NOI18N
            { "s", "catch", "s" },     // 18 CATCH_KEYWORD // NOI18N
            { "", "(", "" },           // 19 STMT_OPEN_BRACKET // NOI18N
            { "", ")", "" },           // 20 STMT_CLOSE_BRACKET // NOI18N
            { "i", "case", "s" },      // 21 CASE_KEYWORD // NOI18N
            { "i", "default", ":" },   // 22 DEFAULT_KEYWORD // NOI18N
            { "s", "?", "s" },         // 23 COND_EXPR_QUESTION // NOI18N
            { "s", ":", "s" },         // 24 COND_EXPR_COLON // NOI18N
            { "i", "do", "s" },        // 25 DO_KEYWORD // NOI18N
            { "s", "while", "s" },     // 26 DO_WHILE_KEYWORD // NOI18N
            { "i", "for", "s" },       // 27 FOR_KEYWORD // NOI18N
            { "", ";", "s" },          // 28 FOR_SEMICOLON // NOI18N
            { "ni", "if", "s" },       // 29 IF_KEYWORD // NOI18N
            { "s", "else", "" },       // 30 ELSE_KEYWORD1 // NOI18N
            { "ni", "else", "" },      // 31 ELSE_KEYWORD2 // NOI18N
            { "s", "{", "" },          // 32 BLOCK_OPEN_CURLY // NOI18N
            { "ni", "}", "" },         // 33 BLOCK_CLOSE_CURLY // NOI18N
            { "i", "switch", "s" },    // 34 SWITCH_KEYWORD // NOI18N
            { "i", "synchronized", "s" },// 35 SYNCHRONIZED_KEYWORD // NOI18N
            { "i", "throw", "s" },     // 36 THROW_KEYWORD // NOI18N
            { "ni", "try", "s" },       // 37 TRY_KEYWORD // NOI18N
            { "s", "finally", "s" },  // 38 FINALLY_KEYWORD // NOI18N
            { "i", "while", "s" },     // 39 WHILE_KEYWORD // NOI18N
        };
    }
    // end temporary

    // formatting constants
    public static final int BODY_OPEN_CURLY = 1;
    public static final int BODY_CLOSE_CURLY = 2;
    public static final int PAR_OPEN_BRACKET = 3;
    public static final int PAR_CLOSE_BRACKET = 4;
    public static final int COMMA = 5;
    public static final int CALLABLE_IDENTIFIER = 6;
    public static final int THROWS_KEYWORD = 7;
    public static final int FIELD_EQUALS = 8;
    public static final int EXTENDS_KEYWORD = 9;
    public static final int IMPLEMENTS_KEYWORD = 10;
    public static final int CLASS_OPEN_CURLY = 11;
    public static final int CLASS_CLOSE_CURLY = 12;
    public static final int ARRAY_OPEN_BRACKET = 13;
    public static final int ARRAY_CLOSE_BRACKET = 14;
    public static final int ARRAY_OPEN_CURLY = 15;
    public static final int ARRAY_CLOSE_CURLY = 16;
    public static final int ASSERT_KEYWORD = 17;
    public static final int CATCH_KEYWORD = 18;
    public static final int STMT_OPEN_BRACKET = 19;
    public static final int STMT_CLOSE_BRACKET = 20;
    public static final int CASE_KEYWORD = 21;
    public static final int DEFAULT_KEYWORD = 22;
    public static final int COND_EXPR_QUESTION = 23;
    public static final int COND_EXPR_COLON = 24;
    public static final int DO_KEYWORD = 25;
    public static final int DO_WHILE_KEYWORD = 26;
    public static final int FOR_KEYWORD = 27;
    public static final int FOR_SEMICOLON = 28;
    public static final int IF_KEYWORD = 29;
    public static final int ELSE_KEYWORD1 = 30;
    public static final int ELSE_KEYWORD2 = 31;
    public static final int BLOCK_OPEN_CURLY = 32;
    public static final int BLOCK_CLOSE_CURLY = 33;
    public static final int SWITCH_KEYWORD = 34;
    public static final int SYNCHRONIZED_KEYWORD = 35;
    public static final int THROW_KEYWORD = 36;
    public static final int TRY_KEYWORD = 37;
    public static final int FINALLY_KEYWORD = 38;
    public static final int WHILE_KEYWORD = 39;

    /**
     * Looks for the formatting used for defined element (type). Puts
     * source representation to the parameter buffer. If the data are not
     * available for the specified formatting type, it throws exception.
     *
     * @param  type  represents type of element which should be formatted
     * @throws IllegalArgumentException  if the formatting for the type
     *         is not available or the formatting data are not accessible
     */
    protected final void formatElementPart(int type, StringBuffer buf) throws IllegalArgumentException {
        if (data == null || type >= data.length) {
            throw new IllegalArgumentException("Format data for the argument " + // NOI18N
                "type #" + type + " not available or formatting data are not " + // NOI18N
                "accessible."); // NOI18N
        }
        // prints leading formatting
        format(data[type][0], buf);
        // prints token representation
        if (data[type][1] != null)
            buf.append(data[type][1]);
        // prints trailing formatting
        format(data[type][2], buf);
    }

    /**
     * @see ...
     * @return  formatted element part
     */
    protected final String formatElementPart(int type) {
        StringBuffer buf = new StringBuffer();
        formatElementPart(type, buf);
        return buf.toString();
    }

    /**
     * Sets the text used before the element and after the
     * element. See ... how strings are interpreted.
     *
     */
    public static final void setFormattingFor(int type, String pre, String post) {
        data[type][0] = pre;
        data[type][2] = post;
    }

    /**
     * Returns the array of the three strings:
     * Characters before the text,
     * formatted text,
     * characters after the text.
     *
     * @return  array of strings
     */
    public static final String[] getFormattingFor(int type) {
        return data[type];
    }

    /**
     * Creates whitespaces from the formatting mask.
     * Format characters representation:
     * n ... new line ('\n') character
     * i ... indentation
     * s ... space
     *
     * @param   mask represents formatting mask
     * @param   buf  buffer to append whitespaces to
     *
     * @return  if anything was added to the buffer
     */
    private boolean format(String mask, StringBuffer buf) {
        if (mask == null || mask.length() == 0)
            return false;

        char[] c = mask.toCharArray();
        for (int i = 0; i < c.length; i++) {
            switch (c[i]) {
                case 'n':
                    buf.append('\n');
                    break;
                case 's':
                    buf.append(' ');
                    break;
                case 'i':
                    buf.append(getIndentation());
                    break;
            }
        }
        return true;
    }

    /**
     * Sets the default indentation of the element.
     *
     * @param  spaces      number of spaces used for indentation
     * @param  expandTabs  if this parameter is true, tab character is used
     *                     instead of spaces
     */
    public static void setIndentSpace(int spaces, boolean expandTabs) {
        if (!expandTabs) {
            // user want to use \t character instead of spaces
            INDENTATION = "\t";
        } else {
            if (spaces >= 0) {
                spacesPerTab = spaces;
                char[] buf = new char[spaces];
                Arrays.fill(buf, ' ');
                INDENTATION = new String(buf);
            }
        }
    }
    
    public static boolean isExpandTab() {
        return !INDENTATION.equals("\t");
    }
    
    public static int getIndentSpace() {
        return spacesPerTab;
    }
    
    protected RefFeatured _immediateComposite() {
        return getRealComposite(super._immediateComposite());
    }

    protected RefFeatured _realImmediateComposite() {
        return super._immediateComposite();
    }

    protected RefFeatured _outermostComposite() {
        return getRealComposite(super._outermostComposite());
    }

    private RefFeatured getRealComposite(RefFeatured refFeatured) {
        if (refFeatured instanceof JavaPackage) {
            JavaPackage pkg = (JavaPackage) refFeatured;
            return ((JavaPackageClass) pkg.refClass()).resolvePackage(pkg.getName());
        } else {
            return refFeatured;
        }
    }

    void childChanged(MetadataElement element) {
    }

    protected final void removeChild(MetadataElement element) {
        replaceChild(element, null);
    }

    public void replaceChild(Element oldElement, Element newElement) {
    }

    protected final boolean replaceObject(List list, Element oldElement, Element newElement) {
        int index=list.indexOf(oldElement);

        if (index!=-1) {
            if (newElement==null)
                list.remove(index);
            else
                list.set(index,newElement);
            return true;
        }
        return false;
    }
}
... 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.