X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-model-api%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fmodel%2Fapi%2FSchemaPath.java;h=6164a8f891d04179768a769c43d30318216ac5b3;hb=aa0d59e9afecc484e8d0e219d3156e7817266e28;hp=6d13ee5f2f45ba2d60ae591050033a5ef25a3cd8;hpb=e9eb6cb98c01ad384936809db1f167fcb964355e;p=yangtools.git diff --git a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaPath.java b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaPath.java index 6d13ee5f2f..6164a8f891 100644 --- a/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaPath.java +++ b/yang/yang-model-api/src/main/java/org/opendaylight/yangtools/yang/model/api/SchemaPath.java @@ -7,55 +7,119 @@ */ package org.opendaylight.yangtools.yang.model.api; +import com.google.common.base.MoreObjects; +import com.google.common.base.MoreObjects.ToStringHelper; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import com.google.common.collect.UnmodifiableIterator; import java.util.Arrays; +import java.util.Iterator; import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.yang.common.QName; /** - * * Represents unique path to the every node inside the module. - * */ -public class SchemaPath { +public abstract class SchemaPath implements Immutable { + + /** + * An absolute SchemaPath. + */ + private static final class AbsoluteSchemaPath extends SchemaPath { + private AbsoluteSchemaPath(final SchemaPath parent, final QName qname) { + super(parent, qname); + } + + @Override + public boolean isAbsolute() { + return true; + } + + @Override + protected SchemaPath createInstance(final SchemaPath parent, final QName qname) { + return new AbsoluteSchemaPath(parent, qname); + } + } + + /** + * A relative SchemaPath. + */ + private static final class RelativeSchemaPath extends SchemaPath { + private RelativeSchemaPath(final SchemaPath parent, final QName qname) { + super(parent, qname); + } + + @Override + public boolean isAbsolute() { + return false; + } + + @Override + protected SchemaPath createInstance(final SchemaPath parent, final QName qname) { + return new RelativeSchemaPath(parent, qname); + } + } + + @SuppressWarnings("rawtypes") + private static final AtomicReferenceFieldUpdater LEGACYPATH_UPDATER = + AtomicReferenceFieldUpdater.newUpdater(SchemaPath.class, ImmutableList.class, "legacyPath"); + /** * Shared instance of the conceptual root schema node. */ - public static final SchemaPath ROOT = new SchemaPath(ImmutableList. of(), true, null); + public static final SchemaPath ROOT = new AbsoluteSchemaPath(null, null); /** * Shared instance of the "same" relative schema node. */ - public static final SchemaPath SAME = new SchemaPath(ImmutableList. of(), false, null); + public static final SchemaPath SAME = new RelativeSchemaPath(null, null); /** - * List of QName instances which represents complete path to the node. + * Parent path. */ - private final ImmutableList path; + private final SchemaPath parent; /** - * Boolean value which represents type of schema path (relative or - * absolute). + * This component. */ - private final Boolean absolute; + private final QName qname; /** - * Constructs new instance of this class with the concrete path. - * - * @param path - * list of QName instances which specifies exact path to the - * module node - * @param absolute - * boolean value which specifies if the path is absolute or - * relative - * - * @deprecated Use {@link #create(Iterable, boolean)} instead. + * Cached hash code. We can use this since we are immutable. */ - @Deprecated - public SchemaPath(final List path, final boolean absolute) { - this(ImmutableList.copyOf(path), absolute, null); + private final int hash; + + /** + * Cached legacy path, filled-in when {@link #getPath()} or {@link #getPathTowardsRoot()} + * is invoked. + */ + private volatile ImmutableList legacyPath; + + protected SchemaPath(final SchemaPath parent, final QName qname) { + this.parent = parent; + this.qname = qname; + + int h = Objects.hashCode(parent); + if (qname != null) { + h = h * 31 + qname.hashCode(); + } + + hash = h; + } + + private ImmutableList getLegacyPath() { + ImmutableList ret = legacyPath; + if (ret == null) { + ret = ImmutableList.copyOf(getPathTowardsRoot()).reverse(); + LEGACYPATH_UPDATER.lazySet(this, ret); + } + + return ret; } /** @@ -68,12 +132,7 @@ public class SchemaPath { */ @Deprecated public List getPath() { - return path; - } - - private SchemaPath(final ImmutableList path, final boolean absolute, final Void dummy) { - this.path = Preconditions.checkNotNull(path); - this.absolute = absolute; + return getLegacyPath(); } /** @@ -89,11 +148,8 @@ public class SchemaPath { * @return A SchemaPath instance. */ public static SchemaPath create(final Iterable path, final boolean absolute) { - if (Iterables.isEmpty(path)) { - return absolute ? ROOT : SAME; - } else { - return new SchemaPath(ImmutableList.copyOf(path), absolute, null); - } + final SchemaPath parent = absolute ? ROOT : SAME; + return parent.createChild(path); } /** @@ -109,9 +165,18 @@ public class SchemaPath { * @return A SchemaPath instance. */ public static SchemaPath create(final boolean absolute, final QName... path) { - return create(Arrays.asList(path), absolute); + return create(Arrays.asList(path), absolute); } + /** + * Create a new instance. + * + * @param parent Parent SchemaPath + * @param qname next path element + * @return A new SchemaPath instance + */ + protected abstract SchemaPath createInstance(SchemaPath parent, QName qname); + /** * Create a child path based on concatenation of this path and a relative path. * @@ -122,7 +187,13 @@ public class SchemaPath { if (Iterables.isEmpty(relative)) { return this; } - return create(Iterables.concat(path, relative), absolute); + + SchemaPath parentPath = this; + for (QName qname : relative) { + parentPath = parentPath.createInstance(parentPath, qname); + } + + return parentPath; } /** @@ -133,7 +204,13 @@ public class SchemaPath { */ public SchemaPath createChild(final SchemaPath relative) { Preconditions.checkArgument(!relative.isAbsolute(), "Child creation requires relative path"); - return createChild(relative.path); + + SchemaPath parentPath = this; + for (QName qname : relative.getPathFromRoot()) { + parentPath = parentPath.createInstance(parentPath, qname); + } + + return parentPath; } /** @@ -156,7 +233,7 @@ public class SchemaPath { * path from the root to the schema node. */ public Iterable getPathFromRoot() { - return path; + return getLegacyPath(); } /** @@ -167,7 +244,48 @@ public class SchemaPath { * path from the schema node towards the root. */ public Iterable getPathTowardsRoot() { - return path.reverse(); + return new Iterable() { + @Override + public Iterator iterator() { + return new UnmodifiableIterator() { + private SchemaPath current = SchemaPath.this; + + @Override + public boolean hasNext() { + return current.parent != null; + } + + @Override + public QName next() { + if (current.parent != null) { + final QName ret = current.qname; + current = current.parent; + return ret; + } else { + throw new NoSuchElementException("No more elements available"); + } + } + }; + } + }; + } + + /** + * Returns the immediate parent SchemaPath. + * + * @return Parent path, null if this SchemaPath is already toplevel. + */ + public SchemaPath getParent() { + return parent; + } + + /** + * Get the last component of this path. + * + * @return The last component of this path. + */ + public final QName getLastComponent() { + return qname; } /** @@ -176,24 +294,11 @@ public class SchemaPath { * @return boolean value which is true if schema path is * absolute. */ - public boolean isAbsolute() { - return absolute; - } + public abstract boolean isAbsolute(); @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + absolute.hashCode(); - - // TODO: Temporary fix for Bug 1076 - hash computation - // Which adds same behaviour as using List.hashCode(). - int pathHash = 1; - for (Object o : path) { - pathHash = prime * pathHash + o.hashCode(); - } - result = prime * result + pathHash; - return result; + public final int hashCode() { + return hash; } @Override @@ -207,22 +312,30 @@ public class SchemaPath { if (getClass() != obj.getClass()) { return false; } - SchemaPath other = (SchemaPath) obj; - if (absolute != other.absolute) { - return false; + final SchemaPath other = (SchemaPath) obj; + + if (qname != null) { + if (!qname.equals(other.qname)) { + return false; + } + } else { + if (other.qname != null) { + return false; + } } - return Iterables.elementsEqual(path, other.path); + if (parent == null) { + return other.parent == null; + } + return parent.equals(other.parent); } @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("SchemaPath [path="); - builder.append(path); - builder.append(", absolute="); - builder.append(absolute); - builder.append("]"); - return builder.toString(); + public final String toString() { + return addToStringAttributes(MoreObjects.toStringHelper(this)).toString(); + } + + protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) { + return toStringHelper.add("path", getPathFromRoot()); } }