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.List;
20 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
22 final class StackedYangInstanceIdentifier extends YangInstanceIdentifier {
23 private static final long serialVersionUID = 1L;
24 private static final Field PARENT_FIELD;
29 f = StackedYangInstanceIdentifier.class.getDeclaredField("parent");
30 } catch (NoSuchFieldException | SecurityException e) {
31 throw new ExceptionInInitializerError(e);
33 f.setAccessible(true);
38 @SuppressWarnings("rawtypes")
39 private static final AtomicReferenceFieldUpdater<StackedYangInstanceIdentifier, ImmutableList> LEGACYPATH_UPDATER =
40 AtomicReferenceFieldUpdater.newUpdater(StackedYangInstanceIdentifier.class, ImmutableList.class, "legacyPath");
42 private final YangInstanceIdentifier parent;
43 private final PathArgument pathArgument;
45 private transient volatile ImmutableList<PathArgument> legacyPath;
46 private transient volatile Iterable<PathArgument> pathArguments;
47 private transient volatile Iterable<PathArgument> reversePathArguments;
49 StackedYangInstanceIdentifier(final YangInstanceIdentifier parent, final PathArgument pathArgument, final int hash) {
51 this.parent = Preconditions.checkNotNull(parent);
52 this.pathArgument = Preconditions.checkNotNull(pathArgument);
56 public YangInstanceIdentifier getParent() {
61 public boolean isEmpty() {
66 public List<PathArgument> getPath() {
67 // Temporary variable saves a volatile read
68 ImmutableList<PathArgument> ret = legacyPath;
70 // We could have used a synchronized block, but the window is quite
71 // small and worst that can happen is duplicate object construction.
72 ret = ImmutableList.copyOf(getPathArguments());
73 LEGACYPATH_UPDATER.lazySet(this, ret);
80 public Iterable<PathArgument> getPathArguments() {
81 Iterable<PathArgument> ret = tryPathArguments();
83 List<StackedYangInstanceIdentifier> stack = new ArrayList<>();
84 YangInstanceIdentifier current = this;
85 while (current.tryPathArguments() == null) {
86 Verify.verify(current instanceof StackedYangInstanceIdentifier);
88 final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) current;
90 current = stacked.getParent();
93 ret = new StackedPathArguments(current, Lists.reverse(stack));
101 public Iterable<PathArgument> getReversePathArguments() {
102 Iterable<PathArgument> ret = reversePathArguments;
104 ret = new StackedReversePathArguments(this);
105 reversePathArguments = ret;
111 public PathArgument getLastPathArgument() {
116 Iterable<PathArgument> tryPathArguments() {
117 return pathArguments;
121 YangInstanceIdentifier createRelativeIdentifier(final int skipFromRoot) {
122 // TODO: can we optimize this one?
123 return YangInstanceIdentifier.create(Iterables.skip(getPathArguments(), skipFromRoot));
127 boolean pathArgumentsEqual(final YangInstanceIdentifier other) {
128 if (other instanceof StackedYangInstanceIdentifier) {
129 final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) other;
130 return pathArgument.equals(stacked.pathArgument) && parent.equals(stacked.parent);
132 return super.pathArgumentsEqual(other);
136 private void readObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
137 inputStream.defaultReadObject();
139 final FixedYangInstanceIdentifier p = (FixedYangInstanceIdentifier) inputStream.readObject();
141 PARENT_FIELD.set(this, p);
142 } catch (IllegalArgumentException | IllegalAccessException e) {
143 throw new IOException("Failed to set parent", e);
147 private void writeObject(final ObjectOutputStream outputStream) throws IOException {
148 outputStream.defaultWriteObject();
150 final FixedYangInstanceIdentifier p;
151 if (parent instanceof FixedYangInstanceIdentifier) {
152 p = (FixedYangInstanceIdentifier) parent;
154 p = FixedYangInstanceIdentifier.create(parent.getPathArguments(), parent.hashCode());
156 outputStream.writeObject(p);