Package org.erlide.engine.internal.model.root

Source Code of org.erlide.engine.internal.model.root.ErlElement$NoResourceSchedulingRule

/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.erlide.engine.internal.model.root;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.erlide.engine.ErlangEngine;
import org.erlide.engine.internal.model.cache.ErlModelCache;
import org.erlide.engine.internal.util.ModelConfig;
import org.erlide.engine.model.ErlModelException;
import org.erlide.engine.model.ErlModelStatus;
import org.erlide.engine.model.ErlModelStatusConstants;
import org.erlide.engine.model.root.ErlElementKind;
import org.erlide.engine.model.root.IErlElement;
import org.erlide.engine.model.root.IErlElementVisitor;
import org.erlide.util.ErlLogger;

import com.google.common.base.Objects;
import com.google.common.collect.Lists;

/**
* Root of Erlang element handle hierarchy.
*
* @see IErlElement
*/
public abstract class ErlElement extends PlatformObject implements IErlElement, Cloneable {

    /**
     * This element's parent, or <code>null</code> if this element does not have
     * a parent.
     */
    private final IErlElement fParent;

    private final List<IErlElement> fChildren = Lists.newArrayList();

    /**
     * This element's name, or an empty <code>String</code> if this element does
     * not have a name.
     */
    protected String fName;

    protected static final Object NO_INFO = new Object();

    /**
     * Constructs a handle for a Erlang element with the given parent element
     * and name.
     *
     * @param parent
     *            The parent of Erlang element
     * @param name
     *            The name of Erlang element
     *
     * @throws IllegalArgumentException
     *             if the type is not one of the valid Erlang element type
     *             constants
     *
     */
    protected ErlElement(final IErlElement parent, final String name) {
        fParent = parent;
        fName = name;
        assertThat(fName, is(not(nullValue())));
    }

    /**
     * This element is being closed. Do any necessary cleanup.
     *
     * @throws ErlModelException
     */
    protected void closing(final Object info) throws ErlModelException {
        for (final IErlElement e : getChildren()) {
            if (e instanceof ErlElement) {
                final ErlElement ee = (ErlElement) e;
                ee.closing(info);
            }
        }
    }

    /**
     * Returns true if this handle represents the same Erlang element as the
     * given handle. By default, two handles represent the same element if they
     * are identical or if they represent the same type of element, have equal
     * names, parents, and occurrence counts.
     *
     * <p>
     * If a subclass has other requirements for equality, this method must be
     * overridden.
     *
     * @see Object#equals
     */
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null) {
            return false;
        }

        // Erlang model parent is null
        if (fParent == null) {
            return super.equals(o);
        }

        if (o instanceof ErlElement) { // WHY OH WHY?!?!?!? This was a tough
            // bug (jc)
            // assume instanceof check is done in subclass
            final ErlElement other = (ErlElement) o;
            return fName.equals(other.fName) && fParent.equals(other.fParent);
        }
        return false;
    }

    /**
     * @see IErlElement
     */
    @Override
    public IErlElement getAncestorOfKind(final ErlElementKind kind) {
        IErlElement element = this;
        while (true) {
            if (element.getKind() == kind) {
                return element;
            }
            final IErlElement parent = element.getParent();
            if (parent != null) {
                element = parent;
            } else {
                break;
            }
        }
        return null;
    }

    /**
     * @see IErlElement
     */
    @Override
    public String getName() {
        return fName;
    }

    /**
     * Return the first instance of IErlElement in the parent hierarchy of this
     * element.
     *
     * <p>
     * Subclasses that are not IErlElement's must override this method.
     */
    public IErlElement getErlElementParent() {
        return fParent;
    }

    /**
     * @see IErlElement
     */
    @Override
    public IErlElement getParent() {
        return fParent;
    }

    static class NoResourceSchedulingRule implements ISchedulingRule {

        public IPath fPath;

        public NoResourceSchedulingRule(final IPath path) {
            fPath = path;
        }

        @Override
        public boolean contains(final ISchedulingRule rule) {
            if (rule instanceof NoResourceSchedulingRule) {
                return fPath.isPrefixOf(((NoResourceSchedulingRule) rule).fPath);
            }
            return false;
        }

        @Override
        public boolean isConflicting(final ISchedulingRule rule) {
            if (rule instanceof NoResourceSchedulingRule) {
                final IPath otherPath = ((NoResourceSchedulingRule) rule).fPath;
                return fPath.isPrefixOf(otherPath) || otherPath.isPrefixOf(fPath);
            }
            return false;
        }
    }

    /**
     * @see IErlElement
     */
    @Override
    public boolean hasChildren() {
        synchronized (getModelLock()) {
            return !internalGetChildren().isEmpty();
        }
    }

    @Override
    public boolean hasChildrenOfKind(final ErlElementKind... kinds) {
        synchronized (getModelLock()) {
            for (final ErlElementKind kind : kinds) {
                for (final IErlElement child : internalGetChildren()) {
                    if (child.getKind() == kind) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * Returns the hash code for this Erlang element. By default, the hash code
     * for an element is a combination of its name and parent's hash code.
     * Elements with other requirements must override this method.
     */
    @Override
    public int hashCode() {
        if (fParent == null) {
            return super.hashCode();
        }
        return Objects.hashCode(fName, fParent);
    }

    /**
     * @see IErlElement
     */
    @Override
    public boolean isReadOnly() {
        return false;
    }

    /**
     */
    public String readableName() {
        return getName();
    }

    protected String tabString(final int tab) {
        return " ";
        // final StringBuilder buffer = new StringBuilder();
        // for (int i = tab; i > 0; i--) {
        // buffer.append(" "); //$NON-NLS-1$
        // }
        // return buffer.toString();
    }

    /**
     * Debugging purposes
     */
    public String toDebugString() {
        final StringBuilder buffer = new StringBuilder();
        this.toStringInfo(0, buffer, NO_INFO);
        return buffer.toString();
    }

    @Override
    public String toString() {
        final StringBuilder buffer = new StringBuilder();
        toString(0, buffer);
        return buffer.toString();
    }

    /**
     * Debugging purposes
     */
    protected void toString(final int tab, final StringBuilder buffer) {
        final Object info = this.toStringInfo(tab, buffer);
        if (tab == 0) {
            // toStringAncestors(buffer);
        }
        toStringChildren(tab, buffer, info);
    }

    /**
     * Debugging purposes
     */
    @Override
    public String toStringWithAncestors() {
        final StringBuilder buffer = new StringBuilder();
        this.toStringInfo(0, buffer, NO_INFO);
        toStringAncestors(buffer);
        return buffer.toString();
    }

    /**
     * Debugging purposes
     */
    protected void toStringAncestors(final StringBuilder buffer) {
        final IErlElement parent = getParent();
        if (parent != null) {
            if (parent instanceof ErlElement) {
                final ErlElement parentElement = (ErlElement) parent;
                buffer.append("[> "); //$NON-NLS-1$
                parentElement.toStringInfo(0, buffer, NO_INFO);
                parentElement.toStringAncestors(buffer);
            }
            buffer.append("] "); //$NON-NLS-1$
        }
    }

    /**
     * Debugging purposes
     */
    protected void toStringChildren(final int tab, final StringBuilder buffer,
            final Object info) {
        if (!(info instanceof ErlElement)) {
            return;
        }
        if (getChildCount() > 0) {
            buffer.append("{");
            int i = 0;
            try {
                for (final IErlElement element : getChildren()) {
                    ((ErlElement) element).toString(tab + 1, buffer);
                    buffer.append(","); //$NON-NLS-1$
                    if (++i > 5) {
                        buffer.append("...");
                        break;
                    }
                }
            } catch (final ErlModelException e) {
            }
            buffer.deleteCharAt(buffer.length() - 1);
            buffer.append("}");
        }
    }

    /**
     * Debugging purposes
     */
    public Object toStringInfo(final int tab, final StringBuilder buffer) {
        this.toStringInfo(tab, buffer, this);
        return this;
    }

    /**
     * Debugging purposes
     */
    protected void toStringInfo(final int tab, final StringBuilder buffer,
            final Object info) {
        buffer.append(tabString(tab));
        buffer.append(getName());
        if (info == null) {
            buffer.append(" (not open)"); //$NON-NLS-1$
        }
    }

    /**
     * Is the structure of this element known
     *
     * @see IErlElement#isStructureKnown()
     */
    protected boolean structureKnown = false;

    @Override
    public void clearCaches() {
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public List<IErlElement> getChildren() throws ErlModelException {
        synchronized (getModelLock()) {
            return Collections
                    .unmodifiableList(Lists.newArrayList(internalGetChildren()));
        }
    }

    public List<IErlElement> internalGetChildren() {
        return fChildren;
    }

    @Override
    public int getChildCount() {
        synchronized (getModelLock()) {
            return internalGetChildren().size();
        }
    }

    /**
     * Returns a collection of (immediate) children of this node of the
     * specified type.
     *
     * @param type
     *            - one of the constants defined by IErlElement
     */
    @Override
    public List<IErlElement> getChildrenOfKind(final ErlElementKind... kinds)
            throws ErlModelException {
        final List<IErlElement> result = Lists.newArrayList();
        synchronized (getModelLock()) {
            for (final ErlElementKind kind : kinds) {
                for (final IErlElement element : internalGetChildren()) {
                    if (element.getKind() == kind) {
                        result.add(element);
                    }
                }
            }
        }
        return result;
    }

    @Override
    public IErlElement getChildNamed(final String name) {
        return getChildNamed(this, name);
    }

    @Override
    public IErlElement getChildWithResource(final IResource rsrc) {
        return getChildWithResource(this, rsrc);
    }

    /**
     * Returns <code>true</code> if this child is in my children collection
     */
    protected boolean includesChild(final IErlElement child) {
        synchronized (getModelLock()) {
            return internalGetChildren().contains(child);
        }
    }

    /**
     * @see IErlElement#isStructureKnown()
     */
    @Override
    public boolean isStructureKnown() {
        return structureKnown;
    }

    @Override
    public void removeChild(final IErlElement child) {
        synchronized (getModelLock()) {
            clearCaches();
            fChildren.remove(child);
        }
    }

    @Override
    public void addChild(final IErlElement child) {
        synchronized (getModelLock()) {
            clearCaches();
            fChildren.add(child);
        }
    }

    @Override
    public void setChildren(final Collection<? extends IErlElement> children) {
        synchronized (getModelLock()) {
            clearCaches();
            fChildren.clear();
            if (children != null) {
                fChildren.addAll(children);
            }
        }
    }

    public void setStructureKnown(final boolean newStructureKnown) {
        structureKnown = newStructureKnown;
    }

    @Override
    public void resourceChanged(final IResourceDelta delta) {
        setStructureKnown(false);
    }

    private static IErlElement getChildNamed(final ErlElement parent, final String name) {
        synchronized (parent.getModelLock()) {
            for (final IErlElement child : parent.internalGetChildren()) {
                if (child.getName().equals(name)) {
                    return child;
                }
            }
        }
        return null;
    }

    protected Object getModelLock() {
        return ErlangEngine.getInstance().getModel().getModelLock();
    }

    private static IErlElement getChildWithResource(final ErlElement parent,
            final IResource rsrc) {
        synchronized (parent.getModelLock()) {
            for (final IErlElement child : parent.internalGetChildren()) {
                if (rsrc.equals(child.getResource())) {
                    return child;
                }
            }
        }
        return null;
    }

    @Override
    public final void accept(final IErlElementVisitor visitor,
            final Set<AcceptFlags> flags, final ErlElementKind leafKind)
            throws ErlModelException {
        synchronized (getModelLock()) {
            internalAccept(visitor, flags, leafKind);
        }
    }

    private final void internalAccept(final IErlElementVisitor visitor,
            final Set<AcceptFlags> flags, final ErlElementKind leafKind)
            throws ErlModelException {
        if (getKind() == leafKind) {
            visitor.visit(this);
        } else {
            boolean visitChildren = true;
            if (!flags.contains(AcceptFlags.LEAFS_ONLY)
                    && !flags.contains(AcceptFlags.CHILDREN_FIRST)) {
                visitChildren = visitor.visit(this);
            }
            if (visitChildren) {
                for (final IErlElement child : internalGetChildren()) {
                    child.accept(visitor, flags, leafKind);
                }
            }
            if (!flags.contains(AcceptFlags.LEAFS_ONLY)
                    && flags.contains(AcceptFlags.CHILDREN_FIRST)) {
                visitor.visit(this);
            }
        }
    }

    /**
     * Return my corresponding resource. Overridden in IErlModule, IErlFolder
     * and IErlProject
     */
    @Override
    public IResource getCorrespondingResource() {
        return null;
    }

    @Override
    public IResource getResource() {
        if (fParent != null) {
            final IErlElement parentElement = fParent;
            return parentElement.getResource();
        }
        return null;
    }

    @Override
    public String getFilePath() {
        return null;
    }

    @Override
    public void dispose() {
        // if (!LOCAL_CHILDREN) {
        // getModel().setChildrenOf(this, null);
        // }
    }

    protected ErlModelCache getModelCache() {
        return ErlModelCache.getDefault();
    }

    // /////////////////////////////////////////////////////

    protected IResource findResult;

    /**
     * Builds this element's structure and properties in the given info object,
     * based on this element's current contents (reuse buffer contents if this
     * element has an open buffer, or resource contents if this element does not
     * have an open buffer). Children are placed in the given newElements table
     * (note, this element has already been placed in the newElements table).
     * Returns true if successful, or false if an error is encountered while
     * determining the structure of this element.
     *
     * @param dirtyRegion
     */
    public abstract boolean buildStructure(IProgressMonitor pm) throws ErlModelException;

    @Override
    public boolean exists() {
        final IResource resource = getResource();
        if (resource != null) {
            return resource.exists();
        }
        return true;
    }

    @Override
    public synchronized void open(final IProgressMonitor monitor)
            throws ErlModelException {
        if (ModelConfig.verbose) {
            ErlLogger.debug("open " + isStructureKnown() + " > " + this);
        }
        // open the parent if necessary
        openParent(monitor);
        if (monitor != null && monitor.isCanceled()) {
            return;
        }

        // build the structure of the ErlElement (this will open the buffer if
        // needed)
        if (!isStructureKnown()) {
            final boolean knownStructure = buildStructure(monitor);
            setStructureKnown(knownStructure);
        }
    }

    class ErlangResourceVisitor implements IResourceVisitor {

        private final String aname;

        public ErlangResourceVisitor(final String name) {
            aname = name;
        }

        @Override
        public boolean visit(final IResource resource) {
            if (resource.getType() == IResource.FILE && resource.getName().equals(aname)) {
                findResult = resource;
                return false;
            }
            // return true to continue visiting children.
            return true;
        }
    }

    /**
     * Returns true if this element may have an associated source buffer,
     * otherwise false. Subclasses must override as required.
     */
    protected boolean hasBuffer() {
        return false;
    }

    @Override
    public boolean hasUnsavedChanges() throws ErlModelException {

        if (isReadOnly() || !isOpen()) {
            return false;
        }
        // final IBuffer buf = this.getBuffer();
        // if (buf != null && buf.hasUnsavedChanges()) {
        // return true;
        // }
        // for packages and projects must check open buffers
        // to see if they have an child with unsaved changes
        final ErlElementKind elementType = getKind();
        if (elementType == ErlElementKind.PROJECT || elementType == ErlElementKind.MODEL) {
            // final Enumeration openBuffers =
            // getBufferManager().getOpenBuffers();
            // while (openBuffers.hasMoreElements()) {
            // final IBuffer buffer = (IBuffer) openBuffers.nextElement();
            // if (buffer.hasUnsavedChanges()) {
            // final IErlElement owner = (IErlElement) buffer.getOwner();
            // if (isAncestorOf(owner)) {
            // return true;
            // }
            // }
            // }
        }

        return false;
    }

    @Override
    public boolean isConsistent() {
        return true;
    }

    @Override
    public boolean isOpen() {
        return true;
    }

    protected boolean isSourceElement() {
        return false;
    }

    @Override
    public void makeConsistent(final IProgressMonitor monitor) throws ErlModelException {
        if (isConsistent()) {
            return;
        }
    }

    protected void openParent(final IProgressMonitor pm) throws ErlModelException {

        final ErlElement ErlElementParent = (ErlElement) getErlElementParent();
        if (ErlElementParent != null && !ErlElementParent.isOpen()) {
            ErlElementParent.open(pm);
        }
    }

    protected boolean parentExists() {
        final IErlElement parent = getParent();
        if (parent == null) {
            return true;
        }
        {
            final IErlElement element = parent;
            return element.exists();
        }
    }

    protected boolean resourceExists() {
        final IWorkspace workspace = ResourcesPlugin.getWorkspace();
        if (workspace == null) {
            return false;
        }
        return ErlangEngine
                .getInstance()
                .getModelUtilService()
                .getTarget(workspace.getRoot(),
                        getResource().getFullPath().makeRelative(), true) != null;
    }

    @Override
    public void save(final IProgressMonitor pm, final boolean force)
            throws ErlModelException {
        if (isReadOnly()) {
            throw new ErlModelException(new ErlModelStatus(
                    ErlModelStatusConstants.READ_ONLY, this));
        }
        // final IBuffer buf = getBuffer();
        // if (buf != null) { // some ErlElements (like a ErlProject) don't have
        // a
        // // buffer
        // buf.save(pm, force);
        // makeConsistent(pm); // update the element info of this
        // // element
        // }
    }

    @Override
    public void close() throws ErlModelException {
        for (final IErlElement child : getChildren()) {
            if (child != null) {
                final IErlElement ErlElement = child;
                if (ErlElement.isOpen()) {
                    ErlElement.close();
                }
            }
        }
        internalGetChildren().clear();
        setStructureKnown(false);
    }

}
TOP

Related Classes of org.erlide.engine.internal.model.root.ErlElement$NoResourceSchedulingRule

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.