2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
3 * This program and the accompanying materials are made available under the
4 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
5 * and is available at http://www.eclipse.org/legal/epl-v10.html
7 package org.opendaylight.yangtools.yang.data.api;
9 import com.google.common.base.Preconditions;
10 import com.google.common.base.Verify;
11 import com.google.common.collect.ImmutableList;
12 import com.google.common.collect.Iterables;
13 import com.google.common.collect.Lists;
14 import java.io.IOException;
15 import java.io.ObjectInputStream;
16 import java.io.ObjectOutputStream;
17 import java.lang.reflect.Field;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.List;
21 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
23 final class StackedYangInstanceIdentifier extends YangInstanceIdentifier {
24 private static final long serialVersionUID = 1L;
25 private static final Field PARENT_FIELD;
30 f = StackedYangInstanceIdentifier.class.getDeclaredField("parent");
31 } catch (NoSuchFieldException | SecurityException e) {
32 throw new ExceptionInInitializerError(e);
34 f.setAccessible(true);
39 @SuppressWarnings("rawtypes")
40 private static final AtomicReferenceFieldUpdater<StackedYangInstanceIdentifier, ImmutableList> LEGACYPATH_UPDATER =
41 AtomicReferenceFieldUpdater.newUpdater(StackedYangInstanceIdentifier.class, ImmutableList.class, "legacyPath");
43 private final YangInstanceIdentifier parent;
44 private final PathArgument pathArgument;
46 private transient volatile ImmutableList<PathArgument> legacyPath;
47 private transient volatile StackedPathArguments pathArguments;
48 private transient volatile StackedReversePathArguments reversePathArguments;
50 StackedYangInstanceIdentifier(final YangInstanceIdentifier parent, final PathArgument pathArgument, final int hash) {
52 this.parent = Preconditions.checkNotNull(parent);
53 this.pathArgument = Preconditions.checkNotNull(pathArgument);
57 public YangInstanceIdentifier getParent() {
62 public boolean isEmpty() {
67 public List<PathArgument> getPath() {
68 // Temporary variable saves a volatile read
69 ImmutableList<PathArgument> ret = legacyPath;
71 // We could have used a synchronized block, but the window is quite
72 // small and worst that can happen is duplicate object construction.
73 ret = ImmutableList.copyOf(getPathArguments());
74 LEGACYPATH_UPDATER.lazySet(this, ret);
81 public Collection<PathArgument> getPathArguments() {
82 StackedPathArguments ret = tryPathArguments();
84 List<PathArgument> stack = new ArrayList<>();
85 YangInstanceIdentifier current = this;
86 while (current.tryPathArguments() == null) {
87 Verify.verify(current instanceof StackedYangInstanceIdentifier);
89 final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) current;
90 stack.add(stacked.getLastPathArgument());
91 current = stacked.getParent();
94 ret = new StackedPathArguments(current, Lists.reverse(stack));
102 public Collection<PathArgument> getReversePathArguments() {
103 StackedReversePathArguments ret = tryReversePathArguments();
105 ret = new StackedReversePathArguments(this);
106 reversePathArguments = ret;
112 public PathArgument getLastPathArgument() {
117 StackedPathArguments tryPathArguments() {
118 return pathArguments;
122 StackedReversePathArguments tryReversePathArguments() {
123 return reversePathArguments;
127 YangInstanceIdentifier createRelativeIdentifier(final int skipFromRoot) {
128 // TODO: can we optimize this one?
129 return YangInstanceIdentifier.create(Iterables.skip(getPathArguments(), skipFromRoot));
133 boolean pathArgumentsEqual(final YangInstanceIdentifier other) {
134 if (other instanceof StackedYangInstanceIdentifier) {
135 final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) other;
136 return pathArgument.equals(stacked.pathArgument) && parent.equals(stacked.parent);
138 return super.pathArgumentsEqual(other);
142 private void readObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
143 inputStream.defaultReadObject();
145 final FixedYangInstanceIdentifier p = (FixedYangInstanceIdentifier) inputStream.readObject();
147 PARENT_FIELD.set(this, p);
148 } catch (IllegalArgumentException | IllegalAccessException e) {
149 throw new IOException("Failed to set parent", e);
153 private void writeObject(final ObjectOutputStream outputStream) throws IOException {
154 outputStream.defaultWriteObject();
156 final FixedYangInstanceIdentifier p;
157 if (parent instanceof FixedYangInstanceIdentifier) {
158 p = (FixedYangInstanceIdentifier) parent;
160 p = FixedYangInstanceIdentifier.create(parent.getPathArguments(), parent.hashCode());
162 outputStream.writeObject(p);