2 * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.controller.cluster.datastore.node.utils.transformer;
10 import static com.google.common.base.Verify.verify;
12 import com.google.common.cache.CacheBuilder;
13 import com.google.common.cache.CacheLoader;
14 import com.google.common.cache.LoadingCache;
15 import com.google.common.collect.ImmutableMap;
16 import java.io.IOException;
17 import java.math.BigInteger;
18 import java.util.HashMap;
20 import java.util.Map.Entry;
21 import java.util.NoSuchElementException;
23 import java.util.function.Function;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.common.Uint16;
27 import org.opendaylight.yangtools.yang.common.Uint32;
28 import org.opendaylight.yangtools.yang.common.Uint64;
29 import org.opendaylight.yangtools.yang.common.Uint8;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
32 import org.opendaylight.yangtools.yang.data.impl.schema.ReusableImmutableNormalizedNodeStreamWriter;
33 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode;
34 import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree;
35 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
39 import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.type.Uint16TypeDefinition;
41 import org.opendaylight.yangtools.yang.model.api.type.Uint32TypeDefinition;
42 import org.opendaylight.yangtools.yang.model.api.type.Uint64TypeDefinition;
43 import org.opendaylight.yangtools.yang.model.api.type.Uint8TypeDefinition;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
47 final class UintAdaptingPruner extends ReusableNormalizedNodePruner {
49 private interface NipAdapter extends Function<NodeIdentifierWithPredicates, NodeIdentifierWithPredicates> {
53 private enum ValueAdapter implements Function<Object, Object> {
56 public Object apply(final Object obj) {
57 if (obj instanceof Short) {
58 LOG.trace("Translating legacy uint8 {}", obj);
59 return Uint8.valueOf((Short) obj);
66 public Object apply(final Object obj) {
67 if (obj instanceof Integer) {
68 LOG.trace("Translating legacy uint16 {}", obj);
69 return Uint16.valueOf((Integer) obj);
76 public Object apply(final Object obj) {
77 if (obj instanceof Long) {
78 LOG.trace("Translating legacy uint32 {}", obj);
79 return Uint32.valueOf((Long) obj);
86 public Object apply(final Object obj) {
87 if (obj instanceof BigInteger) {
88 LOG.trace("Translating legacy uint64 {}", obj);
89 return Uint64.valueOf((BigInteger) obj);
95 private static final Logger LOG = LoggerFactory.getLogger(ValueAdapter.class);
97 static @Nullable ValueAdapter forType(final TypeDefinition<?> type) {
98 if (type instanceof Uint8TypeDefinition) {
100 } else if (type instanceof Uint16TypeDefinition) {
102 } else if (type instanceof Uint32TypeDefinition) {
104 } else if (type instanceof Uint64TypeDefinition) {
112 private static final LoadingCache<ListSchemaNode, NipAdapter> NIP_ADAPTERS = CacheBuilder.newBuilder()
113 .weakKeys().build(new AdapterCacheLoader());
115 UintAdaptingPruner(final DataSchemaContextTree tree) {
120 public ReusableNormalizedNodePruner duplicate() {
121 return new UintAdaptingPruner(getTree());
125 public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
127 enter(this::adaptEntry, identifier, childSizeHint);
131 public void startLeafSetEntryNode(final NodeWithValue<?> name) throws IOException {
132 enter(this::adaptEntry, name);
136 Object translateScalar(final DataSchemaContextNode<?> context, final Object value) throws IOException {
137 final DataSchemaNode schema = context.getDataSchemaNode();
138 return schema instanceof TypedDataSchemaNode ? adaptValue(((TypedDataSchemaNode) schema).getType(), value)
142 private void adaptEntry(final ReusableImmutableNormalizedNodeStreamWriter writer, final NodeWithValue<?> name) {
143 final NodeWithValue<?> adapted;
144 final DataSchemaNode schema = currentSchema().getDataSchemaNode();
145 if (schema instanceof TypedDataSchemaNode) {
146 final Object oldValue = name.getValue();
147 final Object newValue = adaptValue(((TypedDataSchemaNode) schema).getType(), oldValue);
148 adapted = newValue == oldValue ? name : new NodeWithValue<>(name.getNodeType(), newValue);
153 writer.startLeafSetEntryNode(adapted);
156 private void adaptEntry(final ReusableImmutableNormalizedNodeStreamWriter writer,
157 final NodeIdentifierWithPredicates name, final int size) {
158 final NodeIdentifierWithPredicates adapted;
159 final DataSchemaNode schema = currentSchema().getDataSchemaNode();
160 if (schema instanceof ListSchemaNode) {
161 adapted = NIP_ADAPTERS.getUnchecked((ListSchemaNode) schema).apply(name);
166 writer.startMapEntryNode(adapted, size);
169 private static Object adaptValue(final TypeDefinition<?> type, final Object value) {
170 final ValueAdapter adapter = ValueAdapter.forType(type);
171 return adapter != null ? adapter.apply(value) : value;
174 private static final class AdapterCacheLoader extends CacheLoader<ListSchemaNode, NipAdapter> {
176 public NipAdapter load(final ListSchemaNode key) {
177 final Map<QName, ValueAdapter> adapters = new HashMap<>();
179 for (QName qname : key.getKeyDefinition()) {
180 final DataSchemaNode child;
182 child = key.findDataTreeChild(qname).orElseThrow();
183 } catch (NoSuchElementException e) {
184 throw new IllegalStateException("Failed to find child " + qname, e);
187 verify(child instanceof LeafSchemaNode, "Key references non-leaf child %s", child);
188 final ValueAdapter adapter = ValueAdapter.forType(((LeafSchemaNode) child).getType());
189 if (adapter != null) {
190 adapters.put(qname, adapter);
194 return adapters.isEmpty() ? name -> name : new TransformingNipAdapter(adapters);
198 private static final class TransformingNipAdapter implements NipAdapter {
199 private final ImmutableMap<QName, ValueAdapter> adapters;
201 TransformingNipAdapter(final Map<QName, ValueAdapter> toTransform) {
202 adapters = ImmutableMap.copyOf(toTransform);
206 public NodeIdentifierWithPredicates apply(final NodeIdentifierWithPredicates name) {
207 final Set<Entry<QName, Object>> entries = name.entrySet();
208 final ImmutableMap.Builder<QName, Object> newEntries = ImmutableMap.builderWithExpectedSize(entries.size());
209 for (Entry<QName, Object> e : entries) {
210 final QName qname = e.getKey();
211 final ValueAdapter adapter = adapters.get(qname);
212 newEntries.put(qname, adapter != null ? adapter.apply(e.getValue()) : e.getValue());
215 return NodeIdentifierWithPredicates.of(name.getNodeType(), newEntries.build());