001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.reef.tang.implementation.types;
020
021import org.apache.reef.tang.types.Node;
022import org.apache.reef.tang.util.MonotonicTreeMap;
023
024import java.util.Collection;
025import java.util.Map;
026
027public abstract class AbstractNode implements Node {
028  protected final Map<String, Node> children = new MonotonicTreeMap<>();
029  private final Node parent;
030  private final String name;
031  private final String fullName;
032
033  public AbstractNode(final Node parent, final String name, final String fullName) {
034    this.parent = parent;
035    this.name = name;
036    this.fullName = fullName;
037    if (parent != null) {
038      if (name.length() == 0) {
039        throw new IllegalArgumentException(
040            "Zero length child name means bad news");
041      }
042      parent.put(this);
043    }
044  }
045
046  @Override
047  public Collection<Node> getChildren() {
048    return children.values();
049  }
050
051  @Override
052  public String getFullName() {
053    return fullName;
054  }
055
056  @Override
057  public boolean equals(final Object o) {
058    if (this == o) {
059      return true;
060    }
061    if (o == null || getClass() != o.getClass()) {
062      return false;
063    }
064
065    final AbstractNode n = (AbstractNode) o;
066    final boolean parentsEqual;
067    if (n.parent == this.parent) {
068      parentsEqual = true;
069    } else if (n.parent == null) {
070      parentsEqual = false;
071    } else if (this.parent == null) {
072      parentsEqual = false;
073    } else {
074      parentsEqual = n.parent.equals(this.parent);
075    }
076    if (!parentsEqual) {
077      return false;
078    }
079    return this.name.equals(n.name);
080  }
081
082  @Override
083  public int hashCode() {
084    return getFullName().hashCode();
085  }
086
087  @Override
088  public Node getParent() {
089    return parent;
090  }
091
092  @Override
093  public boolean contains(final String key) {
094    return children.containsKey(key);
095  }
096
097  @Override
098  public Node get(final String key) {
099    return children.get(key);
100  }
101
102  @Override
103  public void put(final Node n) {
104    children.put(n.getName(), n);
105  }
106
107  @SuppressWarnings("unused")
108  private String toIndentedString(final int level) {
109    final StringBuilder sb = new StringBuilder();
110    for (int i = 0; i < level; i++) {
111      sb.append("\t");
112    }
113    sb.append(toString() + "\n");
114    if (children != null) {
115      for (final Node n : children.values()) {
116        sb.append(((AbstractNode) n).toIndentedString(level + 1));
117      }
118    }
119    return sb.toString();
120  }
121
122  @Override
123  public String toString() {
124    return "[" + this.getClass().getSimpleName() + " '" + getFullName() + "']";
125  }
126
127  @Override
128  public String getName() {
129    return name;
130  }
131
132  @Override
133  public int compareTo(final Node n) {
134    return getFullName().compareTo(n.getFullName());
135  }
136}