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 java.lang.ref.WeakReference;
import java.lang.reflect.Modifier;
import java.util.*;
import javax.jmi.reflect.ConstraintViolationException;
import javax.jmi.reflect.RefFeatured;
import javax.jmi.reflect.RefObject;
import org.netbeans.api.mdr.events.AssociationEvent;
import org.netbeans.jmi.javamodel.*;
import org.netbeans.lib.java.parser.ASTree;
import org.netbeans.lib.java.parser.Token;
import org.netbeans.mdr.handlers.AttrListWrapper;
import org.netbeans.mdr.handlers.BaseObjectHandler;
import org.netbeans.mdr.persistence.MOFID;
import org.netbeans.mdr.persistence.StorageException;
import org.netbeans.mdr.storagemodel.StorableBaseObject;
import org.netbeans.mdr.storagemodel.StorableObject;
import org.netbeans.modules.javacore.ClassIndex;
import org.netbeans.modules.javacore.ExclusiveMutex;
import org.netbeans.modules.javacore.JMManager;
import org.netbeans.modules.javacore.parser.*;
import org.openide.ErrorManager;
import org.openide.util.Utilities;

/**
 * Implementation of the JavaClass model element.
 *
 * @author  Martin Matula
 * @author  Vlado Hudec
 * @author  Pavel Flaska
 */
public abstract class JavaClassImpl extends FeatureImpl implements JavaClass {
    static final ElementInfo DEFAULT_INFO = new ClassInfo(null, ClassInfo.CLASS_TYPE, null, 0, null, null, null, null, null);

    public static boolean DEBUG = false;
    
    public static final String CONTENTS_ATTR = "contents"; // NOI18N

    private LightAttrList contents = null;

    /** List of interfaces */
    private ReferenceListWrapper interfaces = null;

    private WeakReference subClasses = null;
    private WeakReference implementors = null;

    private boolean internalSetName = false;

    private boolean elementsInited = false;
    private MultipartId superClassName;
    private LightAttrList interfaceNames;
    private final List featuresList;
    private LightAttrList typeParameters;

    /** Creates a new instance of JavaClassImpl */
    public JavaClassImpl(StorableObject s) {
        super(s);
        featuresList = new FeaturesList(this);
    }

    // overrides functionality from FeatureImpl which extracts modifiers from ASTInfo
    public int getModifiers() {
        int mods = super_getModifiers();
        if (isInner()) {
            ClassDefinition cd = getDeclaringClass();
            if (cd instanceof JavaClass && ((JavaClass)cd).isInterface()) {
                mods |= Modifier.STATIC | Modifier.PUBLIC;
            }
        }
        return ~DEPRECATED & mods;
    }

    protected abstract void super_setName(String name);

    /** This method enables to set the whole name of the class (including the package prefix).
     * It is for internal use to synchronize name with changes of the parent package.
     * Users are not able to change other than the simple name part of the name via the standard
     * API.
     */
    void internalSetName(String name) {
        internalSetName = true;
        try {
            if (JMManager.INCONSISTENCY_DEBUG) System.err.println("JavaClassImpl: Changing name of a class using internalSetName.");
            setName(name);
        } finally {
            internalSetName = false;
        }
    }

    public void setName(String name) {
        if (name.equals(getName())) return;
        objectChanged(CHANGED_NAME);
        if (JMManager.INCONSISTENCY_DEBUG) System.err.println("JavaClassImpl: Renaming class " + getName() + " to " + name);
        if (!internalSetName && getResource()!=null && getResource().getPackageName() != null && !name.startsWith(getResource().getPackageName())) {
            throw new ConstraintViolationException(null, null, "Unable to change the package of the class by setting its name (old name: " + getName() + " new name: " + name + " resource package name: " + getResource().getPackageName() + ").");
        }
        
        if (isInitialized() && !isNew()) {
            getElementInfo().hardRefAST();
        }
        
        JavaModelPackage srcExtent=(JavaModelPackage)refOutermostPackage();
        ClassIndex index=ClassIndex.getIndex(srcExtent);
        if (getName() != null) {
            // we have to do rename in class index only in case of there was
            // any name in this class. (Old name was not null.) This is
            // related to issue #44244.
            index.renameClass(this, name);
        } else {
            // the class has no name yet, we have to create it in index
            // right now.
            index.addClass(this, name, this.getSimpleName(name));
        }
        super_setName(name);
        if (isPersisted()) {
            for (Iterator it = getContents().iterator(); it.hasNext();) {
                Object temp = it.next();
                if (temp instanceof JavaClassImpl) {
                    JavaClassImpl cls = (JavaClassImpl) temp;
                    boolean changes = cls.disableChanges;
                    cls.disableChanges |= this.disableChanges;
                    try {
                        cls.internalSetName(name.concat('.' + cls.getSimpleName()));
                    } finally {
                        cls.disableChanges = changes;
                    }
                } else if ((temp instanceof ConstructorImpl) && !disableChanges) {
                    ((ConstructorImpl) temp).objectChanged(CHANGED_NAME);
                }
            }
        } else {
            // [TODO] iterate through inner classes?
        }
    }

    public boolean isInner() {
        String name=getName();
        int lastDot=name.lastIndexOf('.');
        
        if (lastDot!=-1) {
            String outerName=name.substring(0, lastDot);
            ClassIndex index=ClassIndex.getIndex((JavaModelPackage)refImmediatePackage());
            
            return !index.doesnotExist(outerName);
        }
        return false;
    }
    
    /**
     * Returns the value of attribute isInterface.
     * @return Value of attribute isInterface.
     */
    public boolean isInterface() {
        return Modifier.isInterface(getSourceModifiers());
    }

    /**
     * Sets the value of isInterface attribute. See {@link #isInterface} for description
     * on the attribute.
     * @param newValue New value to be set.
     */
    public void setInterface(boolean newValue) {
        if (newValue) {
            setModifiers(getSourceModifiers() | Modifier.INTERFACE);
        } else {
            setModifiers(getSourceModifiers() & ~Modifier.INTERFACE);
        }
    }

    /**
     * Returns the value of reference superInterfaces.
     * @return Value of reference superInterfaces.
     */
    public List getInterfaces() {
        if (interfaces == null) {
            initInterfaces();
        }
        return interfaces;
    }
    
    private void initInterfaces() {
        checkUpToDate();
        List interfaceNames = getInterfaceRefs();
        if (interfaceNames == null) {
            interfaceNames = new ArrayList();
        } else if (!(interfaceNames instanceof ArrayList)) {
            interfaceNames = new ArrayList(interfaceNames);
        }
        // list of superinterfaces is transient
        TypeList _interfaces = new TypeList(this, (ArrayList) interfaceNames) {
            protected void updateParent() {
                setInterfaceRefs(innerList);
            }
        };
        if (interfaces == null) {
            ImplementsImpl implementsImpl = (ImplementsImpl)(((JavaModelPackage) refImmediatePackage()).getImplements());
            interfaces = new ReferenceListWrapper(_getDelegate().getMdrStorage(), implementsImpl, this, "interfaces", this, CHANGED_IMPLEMENTS, _interfaces); // NOI18N
        } else {
            interfaces.setInnerList(_interfaces);
        }
    }

    /**
     * Sets the value of reference superClass. See {@link #getSuperClass} for
     * description on the reference.
     * @param newValue New value to be set.
     */
    public void setSuperClass(JavaClass newValue) {
        Extends source = ((JavaModelPackage) refImmediatePackage()).getExtends();
        if (_getMdrStorage().eventsEnabled()) {
            AssociationEvent event = new AssociationEvent(
                source,
                AssociationEvent.EVENT_ASSOCIATION_SET,
                this,
                "subClasses",
                getSuperClass(),
                newValue,
                AssociationEvent.POSITION_NONE);
            _getMdrStorage().getEventNotifier().ASSOCIATION.firePlannedChange(source, event);
        }
        NameRef sc;
        if (newValue == null) {
            sc = NameRef.java_lang_Object;
            newValue = (JavaClass) resolveType(sc);
        } else {
            sc = (NameRef) typeToTypeRef(newValue);            
        }
        _setSuperClass(sc, (MultipartId) typeRefToTypeReference(sc));
    }
    
    private void _setSuperClass(NameRef superClass, MultipartId superClassName) {
        objectChanged(CHANGED_EXTENDS);
        if (elementsInited) {
            changeChild(getSuperClassName(), superClassName);
            this.superClassName = superClassName;
        }
        setSuperclassRef(superClass);
    }

    public org.netbeans.jmi.javamodel.MultipartId getSuperClassName() {
        if (!elementsInited) {
            initASTElements();
        }
        return superClassName;
    }

    public void setSuperClassName(org.netbeans.jmi.javamodel.MultipartId newValue) {
        NameRef sc = (NameRef) typeReferenceToTypeRef(newValue);
        if (sc == null) {
            sc = NameRef.java_lang_Object;
        }
        _setSuperClass(sc, newValue);
    }

    /**
     * Returns the value of reference superClass.
     * @return Value of reference superClass.
     */
    public JavaClass getSuperClass() {
        JavaClass result;

        // for interfaces and java.lang.Object the superclass is always null
        if ("java.lang.Object".equals(getName())) {
            result = null;
        } else if (isInterface()) {
            result = (JavaClass) resolveType(NameRef.java_lang_Object);

        // if the superclass has changed, the superClass variable is
        // initialized -> return its content
        } else {
            checkUpToDate();
            NameRef superClass = getSuperclassRef();
            if (superClass == null) {
                superClass = NameRef.java_lang_Object;
                setSuperclassRef(superClass);
            }
            result = (JavaClass) resolveType(superClass);
        }

        if (DEBUG) {
            System.out.println("getSuperClass: "+result); // NOI18N
            if (result != null)
                System.out.println("getSuperClass: "+result.getName()); // NOI18N
        }
        return result;
    }

    private Collection getSubClasses(boolean deterministicProgress) {
        if (isInterface()) return Collections.EMPTY_LIST;
        // see whether there already is a reference to the collection of subClasses for
        // the passed class/interface
        ReferenceColWrapper subClasses;
        if (this.subClasses == null || (subClasses = (ReferenceColWrapper) this.subClasses.get()) == null) {
            SubClassesCollection coll = new SubClassesCollection(this, deterministicProgress);
            subClasses = new ReferenceColWrapper(_getMdrStorage(), null, this, null, null, 0, coll);
            this.subClasses = new WeakReference(subClasses);
        }
        return subClasses;
    }
    
    private Collection getImplementors(boolean deterministicProgress) {
        if (!isInterface()) return Collections.EMPTY_LIST;
        ReferenceColWrapper implementors;
        if (this.implementors == null || (implementors = (ReferenceColWrapper) this.implementors.get()) == null) {
            ImplementorsCollection coll = new ImplementorsCollection(this, deterministicProgress);
            implementors = new ReferenceColWrapper(_getMdrStorage(), null, this, null, null, 0, coll);
            this.implementors = new WeakReference(implementors);
        }
        return implementors;
    }
    
    public Collection getSubClasses() {
        return getSubClasses(true);
    }
    
    public Collection getImplementors() {
        return getImplementors(true);
    }
    
    public Collection findSubTypes(boolean transitively) {
        if (!transitively) {
            return isInterface() ? getImplementors() : getSubClasses();
        } else {
            LinkedList q = new LinkedList(getImplementors(false));
            q.addAll(getSubClasses(false));
            HashSet result = new HashSet();
            while (!q.isEmpty()) {
                JavaClassImpl clazz = (JavaClassImpl) q.removeFirst();
                result.add(clazz);
                q.addAll(clazz.getImplementors(false));
                q.addAll(clazz.getSubClasses(false));
            }
            return result;
        }
    }

    public List getPersistentContents() {
        AttrListWrapper list = (AttrListWrapper) super_getContents();
        return ClassDefinitionImpl.getPersistentContent(list);
    }

    /**
     * Returns the value of attribute contents.
     * @return Value of contents attribute.
     */
    public List getContents() {
        if (contents == null) {
            checkUpToDate();
            contents = createChildrenList(CONTENTS_ATTR, (AttrListWrapper) super_getContents(), null, CHANGED_FEATURES);
        }
        return contents;
    }

    public List getFeatures() {
        return featuresList;
    }

    public List getTypeParameters() {
        if (typeParameters == null) {
            checkUpToDate();
            typeParameters = createChildrenList(TYPE_PARAMETERS_ATTR, (AttrListWrapper) super_getTypeParameters(), null, CHANGED_TYPE_PARAMETERS);
        }
        return typeParameters;
    }

    protected abstract List super_getContents();

    public Field getField(String name, boolean includeSupertypes) {
        return ClassDefinitionImpl.getField(this, name, includeSupertypes);
    }

    public Method getMethod(String name, List parameters, boolean includeSupertypes) {
        return ClassDefinitionImpl.getMethod(this, name, parameters, includeSupertypes);
    }

    public JavaClass getInnerClass(String simpleName, boolean includeSupertypes) {
        return ClassDefinitionImpl.getInnerClass(this, simpleName, includeSupertypes);
    }

    public Constructor getConstructor(List parameters, boolean includeSupertypes) {
        return ClassDefinitionImpl.getConstructor(this, parameters, includeSupertypes);
    }

    // ---------------------------------------------------------------------
    // -- Non-JMI public methods -------------------------------------------
    // ---------------------------------------------------------------------

    public void reinitContents() {
        assert contents!=null;
        contents.setInnerList(getPersistentContents(), false);
    }
    
    public boolean contentsInited() {
        return contents != null;
    }
    
    public void setParentClass(JavaClassImpl jcls) {
        try {
            ((StorableObject) _getDelegate()).setComposite(jcls._getDelegate(), null, null);
        } catch (StorageException ex) {
            ErrorManager.getDefault().notify(ex);
        }
        jcls.addInnerClass(this);
    }

    private void addInnerClass(JavaClass javaClass) {
        StorableBaseObject delegate = _getDelegate();
        List inner = (List) delegate.getSlot3();
        if (inner == null) {
            inner = new ArrayList();
        }
        inner.add(javaClass);
        delegate.setSlot3(inner);
    }

    private void removeInnerClass(JavaClass javaClass) {
        StorableBaseObject delegate = _getDelegate();
        List inner = (List) delegate.getSlot3();
        if (inner == null) return;
        if (!inner.remove(javaClass)) {
            inner.remove(((BaseObjectHandler) javaClass)._getDelegate().getMofId());
        }
        delegate.setSlot3(inner);
    }

    // ----------------------------------------------------------------------
    // --- Infrastructural methods ------------------------------------------
    // ----------------------------------------------------------------------

    protected ElementInfo getDefaultInfo() {
        return DEFAULT_INFO;
    }

    protected void matchName(ElementInfo info) {
        if (!Utilities.compareObjects(info.name, this.getName())) {
            internalSetName(info.name);
        }
    }
    
    protected void matchPersistent(ElementInfo info) {
        super.matchPersistent(info);

        ClassInfo newInfo = (ClassInfo) info;
        
        if (!isPersisted()) {
            setPersisted(true);
            persist();
            setSuperclassRef(newInfo.superclass);
            setInterfaceRefs(Arrays.asList(newInfo.interfaces));
            _getDelegate().setSlot3(null);
            persistChildren(super_getContents(), newInfo.features);
            persistChildren(super_getTypeParameters(), newInfo.typeParams);
        } else {
            if (!Utilities.compareObjects(newInfo.superclass, getSuperclassRef())) {
                setSuperClass((JavaClass) resolveType(newInfo.superclass));
            }
            processMembers(getInterfaces(), newInfo.interfaces);
            processMembers(getContents(), newInfo.features);
            processMembers(getTypeParameters(), newInfo.typeParams);
        }
    }
    
    /** The method has to make sure that the AST infos of children are also updated.
     */
    protected void matchElementInfo(ElementInfo newInfo) {
        super.matchElementInfo(newInfo);
        resetASTElements();
    }

    public String toString() {
        return "class " + getName(); // NOI18N
    }

    protected void resetChildren() {
        if (contents != null) contents.setInnerList(getPersistentContents());
        if (typeParameters != null) typeParameters.setInnerList(getPersistentList(TYPE_PARAMETERS_ATTR, super_getTypeParameters()));
        if (childrenInited) {
            resetASTElements();
            initChildren();
        }
        if (interfaces != null) {
            initInterfaces();
        }
    }

    protected List getInitedChildren() {
        List list=new ArrayList();
        if (childrenInited)
            list.addAll(getTypeParameters());
            list.addAll(getContents());
        if (elementsInited) {
            addIfNotNull(list, superClassName);
            list.addAll(interfaceNames);
        }
        return list;
    }

    public List getChildren() {
        List list = new ArrayList();
        list.addAll(getTypeParameters());
        addIfNotNull(list, getSuperClassName());
        list.addAll(getInterfaceNames());
        list.addAll(getContents());
        return list;
    }

    /** This method is called when this element is accessed while bypassing
     * parent (e.g. using getByMofId()) and thus its ASTInfo needs to be
     * initialized by its parent.
     *
     * Preciselly: This method is invoked from getElementInfo of a child object
     * if it finds out that ASTInfo was not initialized by its parent (i.e.
     * this object), yet.
     * This method should also be called whenever a getter method
     * for children of this object is called and the children have not
     * been initialized yet.
     */
    protected void initChildren() {
        // initialization of contents requires writable lock
        boolean fail = true;
        _lock(true);
        try {
            childrenInited = false;
            FeatureInfo[] featureInfos = ((ClassInfo) getElementInfo()).features;
            List featuresCollection = ClassDefinitionImpl.getNakedFeatures(this);
            boolean needsReset = false;
            
            // contents collection was not empty, so it was initialized
            // in the past and should be in sync. - we just need to
            // set ASTInfo to all the elements
            if (!isNew() && (featuresCollection.size() != featureInfos.length)) {
                JMManager.getLog().log("Inconsistent storage. (" + featuresCollection.size() + " != " + featureInfos.length + ")");
                JMManager.getLog().log("recovering...");
                fixMembers(featuresCollection, featureInfos);
                needsReset = true;
            } else {
                ListIterator it = featuresCollection.listIterator();
                for (int i = 0; i < featureInfos.length; i++) {
                    SemiPersistentElement element = (SemiPersistentElement) it.next();
                    if (element instanceof FieldGroup && featureInfos[i] instanceof FieldInfo) {
                        it.remove();
                        element.refDelete();
                        element = createElement(featureInfos[i]);
                        it.add(element);
                        needsReset = true;
                    } else {
                        if (checkElementType(featureInfos[i], element)) {
                            element.setElementInfo(featureInfos[i]);
                        } else {
                            JMManager.getLog().log("Inconsistent storage - feature types do not match. Recovering...");
                            fixMembers(featuresCollection, featureInfos);
                            needsReset = true;
                            break;
                        }
                    }
                }
            }

            // now we need to either create a new wrapper for the
            // contents collection, or if the wrapper already exists,
            // we need to set the collection to it.
            // It is important not to discard the wrapper when doing
            // rollback, so that clients that hold references to it
            // will not break (we will just replace the inner list of
            // the wrapper)
            if (contents != null && needsReset) {
                contents.setInnerList(getPersistentContents());
            }

            typeParameters = createChildrenList(typeParameters, TYPE_PARAMETERS_ATTR, (AttrListWrapper) super_getTypeParameters(), ((ClassInfo) getElementInfo()).typeParams, CHANGED_TYPE_PARAMETERS); // NOI18N

            childrenInited = true;

            if (elementsInited) {
                initASTElements();
            }
            fail = false;
        } catch (RuntimeException e) {
            e.printStackTrace();
            throw e;
        } finally {
            // I do not need to set featuresInitialized to false in
            // case fail == true, since rollback will follow, thus the
            // reset method that already does that will be invoked
            _unlock(fail);
        }
    }

    protected void setData(List annotations, java.lang.String javadocText, JavaDoc javadoc, List features, MultipartId superClassName, List interfaceNames, List typeParameters) {
        super.setData(annotations, javadocText, javadoc);
        this.contents = createChildrenList(CONTENTS_ATTR, (AttrListWrapper) super_getContents(), features, CHANGED_FEATURES); // NOI18N
        changeChild(null, superClassName);
        this.superClassName = superClassName;
        this.interfaceNames = createChildrenList("interfaceNames", interfaceNames, CHANGED_IMPLEMENTS); // NOI18N
        this.typeParameters = createChildrenList(TYPE_PARAMETERS_ATTR, (AttrListWrapper) super_getTypeParameters(), typeParameters, CHANGED_TYPE_PARAMETERS); // NOI18N
        elementsInited = true;
    }
    
    protected abstract List super_getTypeParameters();

    // .........................................................................
    // printing and formatting fuctionality
    // .........................................................................

    /**
     * For the top level classes, do not do indent (use empty string),
     * otherwise use default indentation.
     *
     * @return indentation or empty string in case of top level class
     */
    protected String getIndentation() {
        // if this is inner class, use default indentation defined in
        // semipersitent element, otherwise return empty string as indentation
        RefFeatured composite = refImmediateComposite();
        if (composite instanceof JavaClass || !isNew())
            return super.getIndentation();
        else
            return "";
    }

    public String getSourceText() {
        String origElem;
        if ((origElem = checkChange()) != null)
            return origElem;
        // we have element which is new or changed and moved.
        // todo (#pf): it is possible to leave formatting and comments section
        // as they are in the original element if the element is regenerated.
        // Because it is only rare case, we do not solve it now.    }
        StringBuffer buf = new StringBuffer();
        buf.append('\n');
        generateNewJavaDoc(buf);
        buf.append(getIndentation());
        generateNewModifiers(buf);
        if (!isInterface())
            buf.append("class "); // NOI18N
        buf.append(getSimpleName());
        generateNewTypeParameters(buf);
        if (superClassName != null) {
            formatElementPart(EXTENDS_KEYWORD, buf);
            buf.append(((MetadataElement)superClassName).getSourceText());
        }
        generateNewImplements(buf);
        ClassDefinitionImpl.generateNewFeatures(this, buf, true);
        return buf.toString();
    }

    private void generateNewTypeParameters(StringBuffer buf) {
        Collection typeParameters = getTypeParameters();
        if (!typeParameters.isEmpty()) {
            buf.append('<');
            Iterator it = typeParameters.iterator();
            while (it.hasNext()) {
                buf.append(((TypeParameterImpl) it.next()).getSourceText());
                if (it.hasNext()) {
                    formatElementPart(COMMA, buf);
                }
            }
            buf.append('>');
        }
    }

    /**
     *
     */
    public void getDiff(List diffList) {
        ClassInfo astInfo = (ClassInfo) getElementInfo();
        ASTProvider parser = getParser();
        ASTree[] children = getASTree().getSubTrees();

        // javadoc print
        replaceJavaDoc(diffList);
        // print modifiers
        if (isChanged(CHANGED_MODIFIERS)) {
            diffModifiers(diffList, parser.getToken(children[IDENTIFIER].getFirstToken() - 1), parser);
        }
        // print name
        if (isChanged(CHANGED_NAME)) {
            replaceNode(diffList, parser, children[IDENTIFIER], getSimpleName(), 0, null);
        }

        if (astInfo.typeParams.length == 0) {
            if (isChanged(CHANGED_TYPE_PARAMETERS)) {
                StringBuffer buf = new StringBuffer();
                generateNewTypeParameters(buf);
                int endOffset = getEndOffset(parser, children[IDENTIFIER]);
                diffList.add(new DiffElement(endOffset, endOffset, buf.toString()));
            }
        } else if (getTypeParameters().isEmpty()) {
            if (isChanged(CHANGED_TYPE_PARAMETERS)) {
                replaceNode(diffList, parser, children[2], "", 0, null);
            }
        } else {
            getCollectionDiff(diffList, parser, CHANGED_TYPE_PARAMETERS, astInfo.typeParams, getTypeParameters(), parser.getToken(children[2].getLastToken()).getStartOffset(), ", "); // NOI18N
        }

        // print superclass

        if (isChanged(CHANGED_EXTENDS)) {
            int startOffset, endOffset;
            String extendsText = superClassName == null?"":((MetadataElement) superClassName).getSourceText();
            // if the extends clause exists
            if (children[SUPERCLASS] != null) {
                startOffset = parser.getToken(children[SUPERCLASS].getFirstToken()+(superClassName==null?0:1)).getStartOffset();
                endOffset = parser.getToken(children[SUPERCLASS].getLastToken()).getEndOffset();
            }
            // add whole extends clause
            else {
                startOffset = endOffset = parser.getToken(children[IDENTIFIER].getLastToken()).getEndOffset();
                extendsText = formatElementPart(EXTENDS_KEYWORD) + extendsText;
            }
            diffList.add(new DiffElement(startOffset, endOffset, extendsText));
        } else {
            getChildDiff(diffList, parser, children[SUPERCLASS], (MetadataElement) getSuperClassName(), CHANGED_EXTENDS);
        }


        // interfaces
        int startOffset = parser.getToken(children[children[SUPERCLASS] == null ? IDENTIFIER : SUPERCLASS].getLastToken()).getEndOffset();
        String prefix = isInterface() ? formatElementPart(EXTENDS_KEYWORD) : formatElementPart(IMPLEMENTS_KEYWORD);
        getCollectionDiff(diffList, parser, CHANGED_IMPLEMENTS, getASTree().getSubTrees()[INTERFACES],
                getInterfaceNames(), startOffset, formatElementPart(COMMA), prefix);
        // contents diff
        Token closeBrace = parser.getToken(getASTree().getLastToken());
        Token[] pad = closeBrace.getPadding();
        int endOffset = pad.length > 0 ? pad[0].getStartOffset() : closeBrace.getStartOffset();
        getCollectionDiff(diffList, parser, CHANGED_FEATURES, astInfo.features, getContents(), endOffset, "\n"); // NOI18N
    }

    protected ASTree getPartTree(ElementPartKind part) {
        if (ElementPartKindEnum.NAME.equals(part)) {
            return getASTree().getSubTrees()[IDENTIFIER];
        }
        throw new IllegalArgumentException("Invalid part for this element: " + part); // NOI18N
    }

    public void replaceChild(Element oldElement, Element newElement) {
        if (oldElement instanceof JavaClass && newElement == null) {
            removeInnerClass((JavaClass) oldElement);
        }
        List contents, typeParameters;
        if (isPersisted()) {
            contents = getContents();
            typeParameters = getTypeParameters();
        } else {
            contents = super_getContents();
            typeParameters = super_getTypeParameters();
        }
        if (replaceObject(contents, oldElement, newElement)) return;
        if (replaceObject(typeParameters, oldElement, newElement)) return;
        if (elementsInited) {
            if (oldElement.equals(superClassName)) {
                setSuperClassName((MultipartId) newElement);
                return;
            }
            if (replaceObject(interfaceNames, oldElement, newElement)) return;
        }
        super.replaceChild(oldElement, newElement);
    }

    protected ASTree getPartStartTree(ElementPartKind part) {
        if (ElementPartKindEnum.HEADER.equals(part)) {
            return getASTree();
        }
        return super.getPartStartTree(part);
    }

    protected ASTree getPartEndTree(ElementPartKind part) {
        if (ElementPartKindEnum.HEADER.equals(part)) {
            for (int i = 4; true; i--) {
                ASTree result = getASTree().getSubTrees()[i];
                if (result != null) {
                    return result;
                }
            }
        }
        return super.getPartEndTree(part);
    }

    // useful constants
    private static final int IDENTIFIER = 1;
    private static final int SUPERCLASS = 3;
    private static final int INTERFACES = 4;

    // ---------------------------------------------------------------------
    // --- Private methods -------------------------------------------------
    // ---------------------------------------------------------------------
    /**
     * Prints the whole interfaces clause with the appropriate formatting.
     * (E.g. ' implements java.io.Serializable, java.io.Externalizable ').
     *
     * @param  buf  buffer to append implements clause to
     */
    protected void generateNewImplements(StringBuffer buf) {
        Collection interfaces = getInterfaceNames();
        if (!interfaces.isEmpty()) {
            if (isInterface()) {
                formatElementPart(EXTENDS_KEYWORD, buf);
            } else {
                formatElementPart(IMPLEMENTS_KEYWORD, buf);
            }
            Iterator it = interfaces.iterator();
            MultipartIdImpl impl = (MultipartIdImpl) it.next();
            buf.append(impl.getSourceText());
            while (it.hasNext()) {
                formatElementPart(COMMA, buf);
                impl = (MultipartIdImpl) it.next();
                buf.append(impl.getSourceText());
            }
        }
    }

    public static String getSimpleName(String name) {
        if (name == null) return null;
        int lastDot = name.lastIndexOf('.');

        if (lastDot != -1)
            return name.substring(lastDot + 1);
        return name;
    }

    public String getSimpleName() {
        return getSimpleName(getName());
    }

    public void setSimpleName(String name) {
        String fullName = getName();
        if (fullName!=null) {
            int index = fullName.lastIndexOf('.');
            if (index >= 0) {
                name = fullName.substring(0, index + 1) + name;
            }
        }
        setName(name);
    }

    protected void _delete() {
        if (DEBUG) {
            System.out.println("removing class: " + getName() + " MOFID: " + refMofId()); // NOI18N
            if (refImmediateComposite() != null) {
                System.out.println("    in resource: " + ((NamedElement) refImmediateComposite()).getName()); // NOI18N
            }
            Thread.dumpStack();
        }
        boolean deleteInners = true;
        // --- delete components -------------------------------------------
        // delete all parameters (if initialized)
        deleteChildren(TYPE_PARAMETERS_ATTR, (AttrListWrapper) super_getTypeParameters());
        // delete all contents
        for (Iterator it = getPersistentContents().iterator(); it.hasNext();) {
            RefObject feature = (RefObject) it.next();
            it.remove();
            feature.refDelete();
            deleteInners = false;
        }
        // delete innerclasses
        if (deleteInners) {
            List inner = (List) _getDelegate().getSlot3();
            if (inner != null) {
                for (Iterator it = inner.iterator(); it.hasNext();) {
                    Object temp = it.next();
                    if (temp instanceof MOFID) {
                        temp = _getRepository().getByMofId((MOFID) temp);
                    }
                    JavaClass cls = (JavaClass) temp;
                    it.remove();
                    cls.refDelete();
                }
            }
        }
        _getDelegate().setSlot3(null);
        super._delete();
    }

    protected void parentChanged() {
        parent = refImmediateComposite();
        String prefix;
        if (parent instanceof Resource) {
            prefix = ((Resource) parent).getPackageName();
        } else if (parent instanceof JavaClass) {
            prefix = ((JavaClass) parent).getName();
        } else {
            prefix = "";
        }
        boolean changes = disableChanges;
        disableChanges = true;
        try {
            internalSetName((prefix == null || prefix.length() == 0) ? getSimpleName() : (prefix + '.' + getSimpleName()));
        } finally {
            disableChanges = changes;
        }
    }

    public java.util.List getInterfaceNames() {
        if (!elementsInited) {
            initASTElements();
        }
        return interfaceNames;
    }

    private void initASTElements() {
        elementsInited = false;
        if (!childrenInited) {
            initChildren();
        }
        ClassInfo info = (ClassInfo) getElementInfo();
        ASTree superClass = info.getTypeAST(this);
        ASTree[] interfaces = info.getInterfacesAST(this);
        superClassName = (MultipartId) initOrCreate(superClassName, superClass);
        interfaceNames = createChildrenList(interfaceNames, "interfaceNames", interfaces, CHANGED_IMPLEMENTS, false); // NOI18N
        elementsInited = true;
    }

    private void resetASTElements() {
        if (elementsInited) {
            if (superClassName != null) {
                MultipartId temp = superClassName;
                changeChild(superClassName, null);
                superClassName = null;
                temp.refDelete();
            }
            deleteChildren(interfaceNames);
            interfaceNames = null;
            elementsInited = false;
        }
    }
    
    public boolean isSubTypeOf(ClassDefinition clazz) {
        return ClassDefinitionImpl.isSubTypeOf(this, clazz);
    }
    
    protected void setSuperclassRef(NameRef sc) {
        _getDelegate().setSlot1(sc);
    }
    
    public NameRef getSuperclassRef() {
        return (NameRef) _getDelegate().getSlot1();
    }
    
    protected void setInterfaceRefs(List ifcs) {
        _getDelegate().setSlot2(ifcs);
    }
    
    public List getInterfaceRefs() {
        return (List) _getDelegate().getSlot2();
    }
}
... 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.