Cleanup use of Guava library
[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  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.data.api;
9
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Verify.verify;
12 import static java.util.Objects.requireNonNull;
13
14 import com.google.common.collect.Iterables;
15 import com.google.common.collect.Lists;
16 import java.io.IOException;
17 import java.io.ObjectInputStream;
18 import java.io.ObjectOutputStream;
19 import java.lang.reflect.Field;
20 import java.util.ArrayList;
21 import java.util.List;
22 import javax.annotation.Nonnull;
23
24 final class StackedYangInstanceIdentifier extends YangInstanceIdentifier implements Cloneable {
25     private static final long serialVersionUID = 1L;
26     private static final Field PARENT_FIELD;
27
28     static {
29         final Field f;
30         try {
31             f = StackedYangInstanceIdentifier.class.getDeclaredField("parent");
32         } catch (NoSuchFieldException | SecurityException e) {
33             throw new ExceptionInInitializerError(e);
34         }
35         f.setAccessible(true);
36
37         PARENT_FIELD = f;
38     }
39
40     private final YangInstanceIdentifier parent;
41     private final PathArgument pathArgument;
42
43     private transient volatile StackedPathArguments pathArguments;
44     private transient volatile StackedReversePathArguments reversePathArguments;
45
46     StackedYangInstanceIdentifier(final YangInstanceIdentifier parent, final PathArgument pathArgument,
47             final int hash) {
48         super(hash);
49         this.parent = requireNonNull(parent);
50         this.pathArgument = requireNonNull(pathArgument);
51     }
52
53     @Override
54     public StackedYangInstanceIdentifier clone() {
55         try {
56             return (StackedYangInstanceIdentifier) super.clone();
57         } catch (CloneNotSupportedException e) {
58             throw new IllegalStateException("clone() should be supported", e);
59         }
60     }
61
62     @Override
63     public YangInstanceIdentifier getParent() {
64         return parent;
65     }
66
67     @Nonnull
68     @Override
69     public YangInstanceIdentifier getAncestor(final int depth) {
70         checkArgument(depth >= 0, "Steps cannot be negative");
71
72         // Calculate how far up our FixedYangInstanceIdentifier ancestor is
73         int stackedDepth = 1;
74         YangInstanceIdentifier wlk = getParent();
75         while (wlk instanceof StackedYangInstanceIdentifier) {
76             wlk = wlk.getParent();
77             stackedDepth++;
78         }
79
80         // Guaranteed to come from FixedYangInstanceIdentifier
81         final int fixedDepth = wlk.getPathArguments().size();
82         if (fixedDepth >= depth) {
83             return wlk.getAncestor(depth);
84         }
85
86         // Calculate our depth and check argument
87         final int ourDepth = stackedDepth + fixedDepth;
88         checkArgument(depth <= ourDepth, "Depth %s exceeds maximum depth %s", depth, ourDepth);
89
90         // Requested depth is covered by the stack, traverse up for specified number of steps
91         final int toWalk = ourDepth - depth;
92         YangInstanceIdentifier result = this;
93         for (int i = 0; i < toWalk; ++i) {
94             result = result.getParent();
95         }
96
97         return result;
98     }
99
100     @Override
101     public boolean isEmpty() {
102         return false;
103     }
104
105     @Override
106     public List<PathArgument> getPathArguments() {
107         StackedPathArguments ret = tryPathArguments();
108         if (ret == null) {
109             final List<PathArgument> stack = new ArrayList<>();
110             YangInstanceIdentifier current = this;
111             do {
112                 verify(current instanceof StackedYangInstanceIdentifier);
113                 final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) current;
114                 stack.add(stacked.getLastPathArgument());
115                 current = stacked.getParent();
116             } while (current.tryPathArguments() == null);
117
118             ret = new StackedPathArguments(current, Lists.reverse(stack));
119             pathArguments = ret;
120         }
121
122         return ret;
123     }
124
125     @Override
126     public List<PathArgument> getReversePathArguments() {
127         StackedReversePathArguments ret = tryReversePathArguments();
128         if (ret == null) {
129             ret = new StackedReversePathArguments(this);
130             reversePathArguments = ret;
131         }
132         return ret;
133     }
134
135     @Override
136     public PathArgument getLastPathArgument() {
137         return pathArgument;
138     }
139
140     @Nonnull
141     @Override
142     StackedPathArguments tryPathArguments() {
143         return pathArguments;
144     }
145
146     @Nonnull
147     @Override
148     StackedReversePathArguments tryReversePathArguments() {
149         return reversePathArguments;
150     }
151
152     @Nonnull
153     @Override
154     YangInstanceIdentifier createRelativeIdentifier(final int skipFromRoot) {
155         // TODO: can we optimize this one?
156         return YangInstanceIdentifier.create(Iterables.skip(getPathArguments(), skipFromRoot));
157     }
158
159     @Override
160     boolean pathArgumentsEqual(final YangInstanceIdentifier other) {
161         if (other instanceof StackedYangInstanceIdentifier) {
162             final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) other;
163             return pathArgument.equals(stacked.pathArgument) && parent.equals(stacked.parent);
164         }
165         return super.pathArgumentsEqual(other);
166     }
167
168     private void readObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
169         inputStream.defaultReadObject();
170
171         final FixedYangInstanceIdentifier p = (FixedYangInstanceIdentifier) inputStream.readObject();
172         try {
173             PARENT_FIELD.set(this, p);
174         } catch (IllegalArgumentException | IllegalAccessException e) {
175             throw new IOException("Failed to set parent", e);
176         }
177     }
178
179     private void writeObject(final ObjectOutputStream outputStream) throws IOException {
180         outputStream.defaultWriteObject();
181
182         final FixedYangInstanceIdentifier p;
183         if (parent instanceof FixedYangInstanceIdentifier) {
184             p = (FixedYangInstanceIdentifier) parent;
185         } else {
186             p = FixedYangInstanceIdentifier.create(parent.getPathArguments(), parent.hashCode());
187         }
188         outputStream.writeObject(p);
189     }
190
191     @Override
192     public YangInstanceIdentifier toOptimized() {
193         return FixedYangInstanceIdentifier.create(getPathArguments());
194     }
195 }