9a513aaf62ef0da44a61644a53401ffc4656db8e
[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             final List<PathArgument> stack = new ArrayList<>();
63             YangInstanceIdentifier current = this;
64             do {
65                 Verify.verify(current instanceof StackedYangInstanceIdentifier);
66                 final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) current;
67                 stack.add(stacked.getLastPathArgument());
68                 current = stacked.getParent();
69             } while (current.tryPathArguments() == null);
70
71             ret = new StackedPathArguments(current, Lists.reverse(stack));
72             pathArguments = ret;
73         }
74
75         return ret;
76     }
77
78     @Override
79     public List<PathArgument> getReversePathArguments() {
80         StackedReversePathArguments ret = tryReversePathArguments();
81         if (ret == null) {
82             ret = new StackedReversePathArguments(this);
83             reversePathArguments = ret;
84         }
85         return ret;
86     }
87
88     @Override
89     public PathArgument getLastPathArgument() {
90         return pathArgument;
91     }
92
93     @Override
94     StackedPathArguments tryPathArguments() {
95         return pathArguments;
96     }
97
98     @Override
99     StackedReversePathArguments tryReversePathArguments() {
100         return reversePathArguments;
101     }
102
103     @Override
104     YangInstanceIdentifier createRelativeIdentifier(final int skipFromRoot) {
105         // TODO: can we optimize this one?
106         return YangInstanceIdentifier.create(Iterables.skip(getPathArguments(), skipFromRoot));
107     }
108
109     @Override
110     boolean pathArgumentsEqual(final YangInstanceIdentifier other) {
111         if (other instanceof StackedYangInstanceIdentifier) {
112             final StackedYangInstanceIdentifier stacked = (StackedYangInstanceIdentifier) other;
113             return pathArgument.equals(stacked.pathArgument) && parent.equals(stacked.parent);
114         } else {
115             return super.pathArgumentsEqual(other);
116         }
117     }
118
119     private void readObject(final ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
120         inputStream.defaultReadObject();
121
122         final FixedYangInstanceIdentifier p = (FixedYangInstanceIdentifier) inputStream.readObject();
123         try {
124             PARENT_FIELD.set(this, p);
125         } catch (IllegalArgumentException | IllegalAccessException e) {
126             throw new IOException("Failed to set parent", e);
127         }
128     }
129
130     private void writeObject(final ObjectOutputStream outputStream) throws IOException {
131         outputStream.defaultWriteObject();
132
133         final FixedYangInstanceIdentifier p;
134         if (parent instanceof FixedYangInstanceIdentifier) {
135             p = (FixedYangInstanceIdentifier) parent;
136         } else {
137             p = FixedYangInstanceIdentifier.create(parent.getPathArguments(), parent.hashCode());
138         }
139         outputStream.writeObject(p);
140     }
141
142     @Override
143     public YangInstanceIdentifier toOptimized() {
144         return FixedYangInstanceIdentifier.create(getPathArguments());
145     }
146 }