|
What this is
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 |
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.