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.DataSchemaContext;
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 shortObj) {
58 LOG.trace("Translating legacy uint8 {}", obj);
59 return Uint8.valueOf(shortObj);
66 public Object apply(final Object obj) {
67 if (obj instanceof Integer intObj) {
68 LOG.trace("Translating legacy uint16 {}", obj);
69 return Uint16.valueOf(intObj);
76 public Object apply(final Object obj) {
77 if (obj instanceof Long longObj) {
78 LOG.trace("Translating legacy uint32 {}", obj);
79 return Uint32.valueOf(longObj);
86 public Object apply(final Object obj) {
87 if (obj instanceof BigInteger bigInt) {
88 LOG.trace("Translating legacy uint64 {}", obj);
89 return Uint64.valueOf(bigInt);
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 DataSchemaContext context, final Object value) {
137 final DataSchemaNode schema = context.dataSchemaNode();
138 return schema instanceof TypedDataSchemaNode typed ? adaptValue(typed.getType(), value) : value;
141 private void adaptEntry(final ReusableImmutableNormalizedNodeStreamWriter writer, final NodeWithValue<?> name) {
142 final NodeWithValue<?> adapted;
143 final DataSchemaNode schema = currentSchema().dataSchemaNode();
144 if (schema instanceof TypedDataSchemaNode typed) {
145 final Object oldValue = name.getValue();
146 final Object newValue = adaptValue(typed.getType(), oldValue);
147 adapted = newValue == oldValue ? name : new NodeWithValue<>(name.getNodeType(), newValue);
152 writer.startLeafSetEntryNode(adapted);
155 private void adaptEntry(final ReusableImmutableNormalizedNodeStreamWriter writer,
156 final NodeIdentifierWithPredicates name, final int size) {
157 final NodeIdentifierWithPredicates adapted;
158 final DataSchemaNode schema = currentSchema().dataSchemaNode();
159 if (schema instanceof ListSchemaNode list) {
160 adapted = NIP_ADAPTERS.getUnchecked(list).apply(name);
165 writer.startMapEntryNode(adapted, size);
168 private static Object adaptValue(final TypeDefinition<?> type, final Object value) {
169 final ValueAdapter adapter = ValueAdapter.forType(type);
170 return adapter != null ? adapter.apply(value) : value;
173 private static final class AdapterCacheLoader extends CacheLoader<ListSchemaNode, NipAdapter> {
175 public NipAdapter load(final ListSchemaNode key) {
176 final Map<QName, ValueAdapter> adapters = new HashMap<>();
178 for (QName qname : key.getKeyDefinition()) {
179 final DataSchemaNode child;
181 child = key.findDataTreeChild(qname).orElseThrow();
182 } catch (NoSuchElementException e) {
183 throw new IllegalStateException("Failed to find child " + qname, e);
186 verify(child instanceof LeafSchemaNode, "Key references non-leaf child %s", child);
187 final ValueAdapter adapter = ValueAdapter.forType(((LeafSchemaNode) child).getType());
188 if (adapter != null) {
189 adapters.put(qname, adapter);
193 return adapters.isEmpty() ? name -> name : new TransformingNipAdapter(adapters);
197 private static final class TransformingNipAdapter implements NipAdapter {
198 private final ImmutableMap<QName, ValueAdapter> adapters;
200 TransformingNipAdapter(final Map<QName, ValueAdapter> toTransform) {
201 adapters = ImmutableMap.copyOf(toTransform);
205 public NodeIdentifierWithPredicates apply(final NodeIdentifierWithPredicates name) {
206 final Set<Entry<QName, Object>> entries = name.entrySet();
207 final ImmutableMap.Builder<QName, Object> newEntries = ImmutableMap.builderWithExpectedSize(entries.size());
208 for (Entry<QName, Object> e : entries) {
209 final QName qname = e.getKey();
210 final ValueAdapter adapter = adapters.get(qname);
211 newEntries.put(qname, adapter != null ? adapter.apply(e.getValue()) : e.getValue());
214 return NodeIdentifierWithPredicates.of(name.getNodeType(), newEntries.build());