Package com.intellij.openapi.util.objectTree

Source Code of com.intellij.openapi.util.objectTree.ObjectNode

/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.util.objectTree;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.util.Disposer;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.TestOnly;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;

public final class ObjectNode<T> {
  private static final ObjectNode[] EMPTY_ARRAY = new ObjectNode[0];

  private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.util.objectTree.ObjectNode");

  private final ObjectTree<T> myTree;

  private ObjectNode<T> myParent;
  private final T myObject;

  private LinkedHashSet<ObjectNode<T>> myChildren;
  private final Throwable myTrace;

  private final long myOwnModification;
  private long myChildModification;

  public ObjectNode(ObjectTree<T> tree, ObjectNode<T> parentNode, T object, long modification) {
    myTree = tree;
    myParent = parentNode;
    myObject = object;

    myTrace = Disposer.isDebugMode() ? new Throwable() : null;
    myOwnModification = modification;
  }

  private ObjectNode<T>[] getChildrenArray() {
    synchronized (myTree.treeLock) {
      if (myChildren == null || myChildren.isEmpty()) return EMPTY_ARRAY;
      return myChildren.toArray(new ObjectNode[myChildren.size()]);
    }
  }

  public void addChild(ObjectNode<T> child) {
    synchronized (myTree.treeLock) {
      ensureChildArray();
      child.setParent(this);
      myChildren.add(child);
      myTree.putNode(child.getObject(), child);

      propagateChildModification(child.getModification());
    }
  }

  public void removeChild(ObjectNode<T> child) {
    synchronized (myTree.treeLock) {
      assert myChildren != null: "No children to remove child: " + this + ' ' + child;
      if (myChildren.remove(child)) {
        child.setParent(null);
        myTree.putNode(child.getObject(), null);
        propagateChildModification(myTree.getNextModification());
      }
    }
  }

  private void setParent(ObjectNode<T> parent) {
    synchronized (myTree.treeLock) {
      myParent = parent;
    }
  }

  public ObjectNode<T> getParent() {
    return myParent;
  }

  public Collection<ObjectNode<T>> getChildren() {
    synchronized (myTree.treeLock) {
      if (myChildren == null) return Collections.emptyList();
      return Collections.unmodifiableCollection(myChildren);
    }
  }

  private void ensureChildArray() {
    if (myChildren == null) {
      myChildren = new LinkedHashSet<ObjectNode<T>>();
    }
  }
 
  boolean execute(final boolean disposeTree, final ObjectTreeAction<T> action) {
    ObjectTree.executeActionWithRecursiveGuard(this, new ObjectTreeAction<ObjectNode<T>>() {
      public void execute(ObjectNode<T> each) {
        action.beforeTreeExecution(myObject);

        ObjectNode<T>[] childrenArray = getChildrenArray();
        //todo: [kirillk] optimize

          for (int i = childrenArray.length - 1; i >= 0; i--) {
            childrenArray[i].execute(disposeTree, action);
          }

        if (disposeTree) {
          synchronized (myTree.treeLock) {
            myChildren = null;
          }
        }

        try {
          action.execute(myObject);
          myTree.fireExecuted(myObject);
        }
        catch (ProcessCanceledException e) {
          throw new ProcessCanceledException(e);
        }
        catch (Throwable e) {
          LOG.error(e);
        }

        if (disposeTree) {
          myTree.putNode(myObject, null);
          synchronized (myTree.treeLock) {
            if (myParent != null) {
              myParent.removeChild(ObjectNode.this);
            }
            else {
              myTree.removeRootObject(myObject);
            }
          }
        }
      }

      public void beforeTreeExecution(ObjectNode<T> parent) {

      }
    }, myTree.getNodesInExecution());

    return true;
  }

  public T getObject() {
    return myObject;
  }

  @NonNls
  public String toString() {
    return "Node: " + myObject.toString();
  }

  Throwable getTrace() {
    return myTrace;
  }

  @TestOnly
  void assertNoReferencesKept(T aDisposable) {
    assert getObject() != aDisposable;
    if (myChildren != null) {
      for (ObjectNode<T> node: myChildren) {
        node.assertNoReferencesKept(aDisposable);
      }
    }
  }

  public Throwable getAllocation() {
    return myTrace;
  }

  public long getOwnModification() {
    return myOwnModification;
  }

  public long getChildModification() {
    return myChildModification;
  }

  private void propagateChildModification(long stamp) {
    if (myChildModification < stamp) {
      myChildModification = stamp;
      if (getParent() != null) {
        getParent().propagateChildModification(stamp);
      }
    }
  }

  public long getModification() {
    return Math.max(getOwnModification(), getChildModification());
  }
}
TOP

Related Classes of com.intellij.openapi.util.objectTree.ObjectNode

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.