BUG-3263: return a List of PathArguments
[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.Iterables;
12 import com.google.common.collect.Lists;
13 import java.io.IOException;
14 import java.io.ObjectInputStream;
15 import java.io.ObjectOutputStream;
16 import java.lang.reflect.Field;
17 import java.util.ArrayList;
18 import java.util.List;
19
20 final class StackedYangInstanceIdentifier extends YangInstanceIdentifier {
21     private static final long serialVersionUID = 1L;
22     private static final Field PARENT_FIELD;
23
24     static {
25         final Field f;
26         try {
27             f = StackedYangInstanceIdentifier.class.getDeclaredField("parent");
28         } catch (NoSuchFieldException | SecurityException e) {
29             throw new ExceptionInInitializerError(e);
30         }
31         f.setAccessible(true);
32
33         PARENT_FIELD = f;
34     }
35
36     private final YangInstanceIdentifier parent;
37     private final PathArgument pathArgument;
38
39     private transient volatile StackedPathArguments pathArguments;
40     private transient volatile StackedReversePathArguments reversePathArguments;
41
42     StackedYangInstanceIdentifier(final YangInstanceIdentifier parent, final PathArgument pathArgument, final int hash) {
43         super(hash);
44         this.parent = Preconditions.checkNotNull(parent);
45         this.pathArgument = Preconditions.checkNotNull(pathArgument);
46     }
47
48     @Override
49     public YangInstanceIdentifier getParent() {
50         return parent;
51     }
52
53     @Override
54     public boolean isEmpty() {
55         return false;
56     }
57
58     @Override
59     public List<PathArgument> getPathArguments() {
60         StackedPathArguments ret = tryPathArguments();
61         if (ret == null) {
62             List<PathArgument> stack = new ArrayList<>();
63             YangInstanceIdentifier current = this;
64             while (current.tryPathArguments() == null) {
65                 Verify.verify(current instanceof StackedYangInstanceIdentifier);
66
67                 final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) current;
68                 stack.add(stacked.getLastPathArgument());
69                 current = stacked.getParent();
70             }
71
72             ret = new StackedPathArguments(current, Lists.reverse(stack));
73             pathArguments = ret;
74         }
75
76         return ret;
77     }
78
79     @Override
80     public List<PathArgument> getReversePathArguments() {
81         StackedReversePathArguments ret = tryReversePathArguments();
82         if (ret == null) {
83             ret = new StackedReversePathArguments(this);
84             reversePathArguments = ret;
85         }
86         return ret;
87     }
88
89     @Override
90     public PathArgument getLastPathArgument() {
91         return pathArgument;
92     }
93
94     @Override
95     StackedPathArguments tryPathArguments() {
96         return pathArguments;
97     }
98
99     @Override
100     StackedReversePathArguments tryReversePathArguments() {
101         return reversePathArguments;
102     }
103
104     @Override
105     YangInstanceIdentifier createRelativeIdentifier(final int skipFromRoot) {
106         // TODO: can we optimize this one?
107         return YangInstanceIdentifier.create(Iterables.skip(getPathArguments(), skipFromRoot));
108     }
109
110     @Override
111     boolean pathArgumentsEqual(final YangInstanceIdentifier other) {
112         if (other instanceof StackedYangInstanceIdentifier) {
113             final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) other;
114             return pathArgument.equals(stacked.pathArgument) && parent.equals(stacked.parent);
115         } else {
116             return super.pathArgumentsEqual(other);
117         }
118     }
119
120     private void readObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
121         inputStream.defaultReadObject();
122
123         final FixedYangInstanceIdentifier p = (FixedYangInstanceIdentifier) inputStream.readObject();
124         try {
125             PARENT_FIELD.set(this, p);
126         } catch (IllegalArgumentException | IllegalAccessException e) {
127             throw new IOException("Failed to set parent", e);
128         }
129     }
130
131     private void writeObject(final ObjectOutputStream outputStream) throws IOException {
132         outputStream.defaultWriteObject();
133
134         final FixedYangInstanceIdentifier p;
135         if (parent instanceof FixedYangInstanceIdentifier) {
136             p = (FixedYangInstanceIdentifier) parent;
137         } else {
138             p = FixedYangInstanceIdentifier.create(parent.getPathArguments(), parent.hashCode());
139         }
140         outputStream.writeObject(p);
141     }
142 }