Transform QName value in identity leaf
[yangtools.git] / yang / yang-data-transform / src / main / java / org / opendaylight / yangtools / transform / QNameTransformingStreamWriter.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.transform;
9
10 import com.google.common.collect.ImmutableSet;
11 import java.io.IOException;
12 import java.util.HashMap;
13 import java.util.Map;
14 import java.util.function.Function;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.common.QNameModule;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
22 import org.opendaylight.yangtools.yang.data.api.schema.stream.ForwardingNormalizedNodeStreamWriter;
23 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
24
25 /**
26  * Stateless Normalized Node Stream Writer decorator, which performs QName translation.
27  *
28  * <p>
29  * This class serves as base for Normalized Node Stream Writer decorators with option to transform
30  * QNames by user-implemented {@link #transform(QName)} function.
31  */
32 public abstract class QNameTransformingStreamWriter extends ForwardingNormalizedNodeStreamWriter {
33
34     // FIXME: Probably use loading cache to decrease memory
35
36     /**
37      * Returns decorator, which uses supplied function to transform QNames.
38      *
39      * @param delegate Underlying normalized node stream writer
40      * @param transformation Transformation function, function is required to return non-null
41      *        values.
42      * @return decorator, which uses supplied function to transform QNames.
43      */
44     public static NormalizedNodeStreamWriter fromFunction(final NormalizedNodeStreamWriter delegate,
45             final Function<QName, QName> transformation) {
46         return new QNameTransformingStreamWriter() {
47
48             @Override
49             protected NormalizedNodeStreamWriter delegate() {
50                 return delegate;
51             }
52
53             @Override
54             protected QName transform(final QName key) {
55                 return transformation.apply(key);
56             }
57         };
58     }
59
60     /**
61      * Returns decorator, which uses supplied map to transform QNames. QNames not present in map are left unchanged.
62      *
63      * @param delegate Underlying normalized node stream writer
64      * @param mapping Immutable map which represent mapping from original to new values.
65      * @return decorator, which uses supplied mapping to transform QNames.
66      */
67     public static NormalizedNodeStreamWriter createQNameReplacing(final NormalizedNodeStreamWriter delegate,
68             final Map<QName, QName> mapping) {
69         return fromFunction(delegate, new QNameReplacementFunction(mapping));
70     }
71
72     /**
73      * Returns decorator, which uses supplied map to transform QNameModules. QNameModules not present in map are left
74      * unchanged.
75      *
76      * @param delegate Underlying normalized node stream writer
77      * @param mapping Immutable map which represent mapping from original to new values.
78      * @return decorator, which uses supplied mapping to transform QNameModules.
79      */
80     public static NormalizedNodeStreamWriter createQNameModuleReplacing(final NormalizedNodeStreamWriter delegate,
81             final Map<QNameModule, QNameModule> mapping) {
82         return fromFunction(delegate, new QNameModuleReplacementFunction(mapping));
83     }
84
85     @Override
86     public void startLeafNode(final NodeIdentifier name) throws IOException {
87         super.startLeafNode(transform(name));
88     }
89
90     @Override
91     public void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
92         super.startLeafSet(transform(name), childSizeHint);
93     }
94
95     @Override
96     public void startOrderedLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
97         super.startOrderedLeafSet(transform(name), childSizeHint);
98     }
99
100     @Override
101     public void startLeafSetEntryNode(final NodeWithValue<?> name) throws IOException {
102         super.startLeafSetEntryNode(transform(name));
103     }
104
105     @Override
106     public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
107         super.startContainerNode(transform(name), childSizeHint);
108     }
109
110     @Override
111     public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IOException {
112         super.startUnkeyedList(transform(name), childSizeHint);
113     }
114
115     @Override
116     public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException {
117         super.startUnkeyedListItem(transform(name), childSizeHint);
118     }
119
120     @Override
121     public void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
122         super.startMapNode(transform(name), childSizeHint);
123     }
124
125     @Override
126     public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
127             throws IOException {
128         super.startMapEntryNode(transform(identifier), childSizeHint);
129     }
130
131     @Override
132     public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
133         super.startOrderedMapNode(transform(name), childSizeHint);
134     }
135
136     @Override
137     public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
138         super.startChoiceNode(transform(name), childSizeHint);
139     }
140
141     @Override
142     public void startAugmentationNode(final AugmentationIdentifier identifier) throws IOException {
143         super.startAugmentationNode(transform(identifier));
144     }
145
146     @Override
147     public boolean startAnyxmlNode(final NodeIdentifier name, final Class<?> objectModel) throws IOException {
148         return super.startAnyxmlNode(transform(name), objectModel);
149     }
150
151     @Override
152     public void startYangModeledAnyXmlNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
153         super.startYangModeledAnyXmlNode(transform(name), childSizeHint);
154     }
155
156     @Override
157     public void scalarValue(final Object value) throws IOException {
158         // identityref leaf nodes contain identity QName as a value - it needs to be transformed
159         super.scalarValue(value instanceof QName ? transform((QName) value) : value);
160     }
161
162     /**
163      * Transforms a QName to new mapping.
164      *
165      * <p>
166      * NOTE: If QName should be unchanged implementation needs to return original QName.
167      *
168      * @param key QName to transform.
169      * @return Returns new value of QName.
170      */
171     protected abstract @NonNull QName transform(@NonNull QName key);
172
173     private NodeIdentifier transform(final NodeIdentifier name) {
174         final QName original = name.getNodeType();
175         final QName transformed = transform(original);
176         return transformed == original ? name : new NodeIdentifier(transformed);
177     }
178
179     private <T> NodeWithValue<T> transform(final NodeWithValue<T> name) {
180         final QName original = name.getNodeType();
181         final QName transformed = transform(original);
182         return transformed == original ? name : new NodeWithValue<>(transformed, name.getValue());
183     }
184
185     private AugmentationIdentifier transform(final AugmentationIdentifier identifier) {
186         ImmutableSet.Builder<QName> builder = ImmutableSet.builder();
187         for (QName original : identifier.getPossibleChildNames()) {
188             builder.add(transform(original));
189         }
190         return new AugmentationIdentifier(builder.build());
191     }
192
193     private NodeIdentifierWithPredicates transform(final NodeIdentifierWithPredicates identifier) {
194         Map<QName, Object> keyValues = new HashMap<>();
195         for (Map.Entry<QName, Object> original : identifier.entrySet()) {
196             keyValues.put(transform(original.getKey()), original.getValue());
197         }
198         return NodeIdentifierWithPredicates.of(transform(identifier.getNodeType()), keyValues);
199     }
200 }