Fix eclipse/checkstyle warnings
[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 com.google.common.base.Preconditions;
11 import com.google.common.base.Verify;
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 javax.annotation.Nonnull;
21
22 final class StackedYangInstanceIdentifier extends YangInstanceIdentifier implements Cloneable {
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     private final YangInstanceIdentifier parent;
39     private final PathArgument pathArgument;
40
41     private transient volatile StackedPathArguments pathArguments;
42     private transient volatile StackedReversePathArguments reversePathArguments;
43
44     StackedYangInstanceIdentifier(final YangInstanceIdentifier parent, final PathArgument pathArgument,
45             final int hash) {
46         super(hash);
47         this.parent = Preconditions.checkNotNull(parent);
48         this.pathArgument = Preconditions.checkNotNull(pathArgument);
49     }
50
51     @Override
52     public StackedYangInstanceIdentifier clone() {
53         try {
54             return (StackedYangInstanceIdentifier) super.clone();
55         } catch (CloneNotSupportedException e) {
56             throw new IllegalStateException("clone() should be supported", e);
57         }
58     }
59
60     @Override
61     public YangInstanceIdentifier getParent() {
62         return parent;
63     }
64
65     @Nonnull
66     @Override
67     public YangInstanceIdentifier getAncestor(final int depth) {
68         Preconditions.checkArgument(depth >= 0, "Steps cannot be negative");
69
70         // Calculate how far up our FixedYangInstanceIdentifier ancestor is
71         int stackedDepth = 1;
72         YangInstanceIdentifier wlk = getParent();
73         while (wlk instanceof StackedYangInstanceIdentifier) {
74             wlk = wlk.getParent();
75             stackedDepth++;
76         }
77
78         // Guaranteed to come from FixedYangInstanceIdentifier
79         final int fixedDepth = wlk.getPathArguments().size();
80         if (fixedDepth >= depth) {
81             return wlk.getAncestor(depth);
82         }
83
84         // Calculate our depth and check argument
85         final int ourDepth = stackedDepth + fixedDepth;
86         Preconditions.checkArgument(depth <= ourDepth, "Depth %s exceeds maximum depth %s", depth, ourDepth);
87
88         // Requested depth is covered by the stack, traverse up for specified number of steps
89         final int toWalk = ourDepth - depth;
90         YangInstanceIdentifier result = this;
91         for (int i = 0; i < toWalk; ++i) {
92             result = result.getParent();
93         }
94
95         return result;
96     }
97
98     @Override
99     public boolean isEmpty() {
100         return false;
101     }
102
103     @Override
104     public List<PathArgument> getPathArguments() {
105         StackedPathArguments ret = tryPathArguments();
106         if (ret == null) {
107             final List<PathArgument> stack = new ArrayList<>();
108             YangInstanceIdentifier current = this;
109             do {
110                 Verify.verify(current instanceof StackedYangInstanceIdentifier);
111                 final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) current;
112                 stack.add(stacked.getLastPathArgument());
113                 current = stacked.getParent();
114             } while (current.tryPathArguments() == null);
115
116             ret = new StackedPathArguments(current, Lists.reverse(stack));
117             pathArguments = ret;
118         }
119
120         return ret;
121     }
122
123     @Override
124     public List<PathArgument> getReversePathArguments() {
125         StackedReversePathArguments ret = tryReversePathArguments();
126         if (ret == null) {
127             ret = new StackedReversePathArguments(this);
128             reversePathArguments = ret;
129         }
130         return ret;
131     }
132
133     @Override
134     public PathArgument getLastPathArgument() {
135         return pathArgument;
136     }
137
138     @Nonnull
139     @Override
140     StackedPathArguments tryPathArguments() {
141         return pathArguments;
142     }
143
144     @Nonnull
145     @Override
146     StackedReversePathArguments tryReversePathArguments() {
147         return reversePathArguments;
148     }
149
150     @Nonnull
151     @Override
152     YangInstanceIdentifier createRelativeIdentifier(final int skipFromRoot) {
153         // TODO: can we optimize this one?
154         return YangInstanceIdentifier.create(Iterables.skip(getPathArguments(), skipFromRoot));
155     }
156
157     @Override
158     boolean pathArgumentsEqual(final YangInstanceIdentifier other) {
159         if (other instanceof StackedYangInstanceIdentifier) {
160             final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) other;
161             return pathArgument.equals(stacked.pathArgument) && parent.equals(stacked.parent);
162         }
163         return super.pathArgumentsEqual(other);
164     }
165
166     private void readObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
167         inputStream.defaultReadObject();
168
169         final FixedYangInstanceIdentifier p = (FixedYangInstanceIdentifier) inputStream.readObject();
170         try {
171             PARENT_FIELD.set(this, p);
172         } catch (IllegalArgumentException | IllegalAccessException e) {
173             throw new IOException("Failed to set parent", e);
174         }
175     }
176
177     private void writeObject(final ObjectOutputStream outputStream) throws IOException {
178         outputStream.defaultWriteObject();
179
180         final FixedYangInstanceIdentifier p;
181         if (parent instanceof FixedYangInstanceIdentifier) {
182             p = (FixedYangInstanceIdentifier) parent;
183         } else {
184             p = FixedYangInstanceIdentifier.create(parent.getPathArguments(), parent.hashCode());
185         }
186         outputStream.writeObject(p);
187     }
188
189     @Override
190     public YangInstanceIdentifier toOptimized() {
191         return FixedYangInstanceIdentifier.create(getPathArguments());
192     }
193 }