dc803ece58e5a94b43e13daf0a89929c88f591b4
[yangtools.git] / yang / yang-data-api / src / main / java / org / opendaylight / yangtools / yang / data / api / StackedYangInstanceIdentifier.java
1 /*
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
6  */
7 package org.opendaylight.yangtools.yang.data.api;
8
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;
21
22 final class StackedYangInstanceIdentifier extends YangInstanceIdentifier {
23     private static final long serialVersionUID = 1L;
24     private static final Field PARENT_FIELD;
25
26     static {
27         final Field f;
28         try {
29             f = StackedYangInstanceIdentifier.class.getDeclaredField("parent");
30         } catch (NoSuchFieldException | SecurityException e) {
31             throw new ExceptionInInitializerError(e);
32         }
33         f.setAccessible(true);
34
35         PARENT_FIELD = f;
36     }
37
38     @SuppressWarnings("rawtypes")
39     private static final AtomicReferenceFieldUpdater<StackedYangInstanceIdentifier, ImmutableList> LEGACYPATH_UPDATER =
40             AtomicReferenceFieldUpdater.newUpdater(StackedYangInstanceIdentifier.class, ImmutableList.class, "legacyPath");
41
42     private final YangInstanceIdentifier parent;
43     private final PathArgument pathArgument;
44
45     private transient volatile ImmutableList<PathArgument> legacyPath;
46     private transient volatile Iterable<PathArgument> pathArguments;
47     private transient volatile Iterable<PathArgument> reversePathArguments;
48
49     StackedYangInstanceIdentifier(final YangInstanceIdentifier parent, final PathArgument pathArgument, final int hash) {
50         super(hash);
51         this.parent = Preconditions.checkNotNull(parent);
52         this.pathArgument = Preconditions.checkNotNull(pathArgument);
53     }
54
55     @Override
56     public YangInstanceIdentifier getParent() {
57         return parent;
58     }
59
60     @Override
61     public boolean isEmpty() {
62         return false;
63     }
64
65     @Override
66     public List<PathArgument> getPath() {
67         // Temporary variable saves a volatile read
68         ImmutableList<PathArgument> ret = legacyPath;
69         if (ret == null) {
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);
74         }
75
76         return ret;
77     }
78
79     @Override
80     public Iterable<PathArgument> getPathArguments() {
81         Iterable<PathArgument> ret = tryPathArguments();
82         if (ret == null) {
83             List<StackedYangInstanceIdentifier> stack = new ArrayList<>();
84             YangInstanceIdentifier current = this;
85             while (current.tryPathArguments() == null) {
86                 Verify.verify(current instanceof StackedYangInstanceIdentifier);
87
88                 final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) current;
89                 stack.add(stacked);
90                 current = stacked.getParent();
91             }
92
93             ret = new StackedPathArguments(current, Lists.reverse(stack));
94             pathArguments = ret;
95         }
96
97         return ret;
98     }
99
100     @Override
101     public Iterable<PathArgument> getReversePathArguments() {
102         Iterable<PathArgument> ret = reversePathArguments;
103         if (ret == null) {
104             ret = new StackedReversePathArguments(this);
105             reversePathArguments = ret;
106         }
107         return ret;
108     }
109
110     @Override
111     public PathArgument getLastPathArgument() {
112         return pathArgument;
113     }
114
115     @Override
116     Iterable<PathArgument> tryPathArguments() {
117         return pathArguments;
118     }
119
120     @Override
121     YangInstanceIdentifier createRelativeIdentifier(final int skipFromRoot) {
122         // TODO: can we optimize this one?
123         return YangInstanceIdentifier.create(Iterables.skip(getPathArguments(), skipFromRoot));
124     }
125
126     @Override
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);
131         } else {
132             return super.pathArgumentsEqual(other);
133         }
134     }
135
136     private void readObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
137         inputStream.defaultReadObject();
138
139         final FixedYangInstanceIdentifier p = (FixedYangInstanceIdentifier) inputStream.readObject();
140         try {
141             PARENT_FIELD.set(this, p);
142         } catch (IllegalArgumentException | IllegalAccessException e) {
143             throw new IOException("Failed to set parent", e);
144         }
145     }
146
147     private void writeObject(final ObjectOutputStream outputStream) throws IOException {
148         outputStream.defaultWriteObject();
149
150         final FixedYangInstanceIdentifier p;
151         if (parent instanceof FixedYangInstanceIdentifier) {
152             p = (FixedYangInstanceIdentifier) parent;
153         } else {
154             p = FixedYangInstanceIdentifier.create(parent.getPathArguments(), parent.hashCode());
155         }
156         outputStream.writeObject(p);
157     }
158 }