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