Improve segmented journal actor metrics
[controller.git] / opendaylight / md-sal / sal-clustering-commons / src / main / java / org / opendaylight / controller / cluster / datastore / node / utils / transformer / UintAdaptingPruner.java
1 /*
2  * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.controller.cluster.datastore.node.utils.transformer;
9
10 import static com.google.common.base.Verify.verify;
11
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;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import java.util.NoSuchElementException;
22 import java.util.Set;
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;
46
47 final class UintAdaptingPruner extends ReusableNormalizedNodePruner {
48     @FunctionalInterface
49     private interface NipAdapter extends Function<NodeIdentifierWithPredicates, NodeIdentifierWithPredicates> {
50
51     }
52
53     private enum ValueAdapter implements Function<Object, Object> {
54         UINT8 {
55             @Override
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);
60                 }
61                 return obj;
62             }
63         },
64         UINT16 {
65             @Override
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);
70                 }
71                 return obj;
72             }
73         },
74         UINT32 {
75             @Override
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);
80                 }
81                 return obj;
82             }
83         },
84         UINT64 {
85             @Override
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);
90                 }
91                 return obj;
92             }
93         };
94
95         private static final Logger LOG = LoggerFactory.getLogger(ValueAdapter.class);
96
97         static @Nullable ValueAdapter forType(final TypeDefinition<?> type) {
98             if (type instanceof Uint8TypeDefinition) {
99                 return UINT8;
100             } else if (type instanceof Uint16TypeDefinition) {
101                 return UINT16;
102             } else if (type instanceof Uint32TypeDefinition) {
103                 return UINT32;
104             } else if (type instanceof Uint64TypeDefinition) {
105                 return UINT64;
106             } else {
107                 return null;
108             }
109         }
110     }
111
112     private static final LoadingCache<ListSchemaNode, NipAdapter> NIP_ADAPTERS = CacheBuilder.newBuilder()
113             .weakKeys().build(new AdapterCacheLoader());
114
115     UintAdaptingPruner(final DataSchemaContextTree tree) {
116         super(tree);
117     }
118
119     @Override
120     public ReusableNormalizedNodePruner duplicate() {
121         return new UintAdaptingPruner(getTree());
122     }
123
124     @Override
125     public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
126             throws IOException {
127         enter(this::adaptEntry, identifier, childSizeHint);
128     }
129
130     @Override
131     public void startLeafSetEntryNode(final NodeWithValue<?> name) throws IOException {
132         enter(this::adaptEntry, name);
133     }
134
135     @Override
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;
139     }
140
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);
148         } else {
149             adapted = name;
150         }
151
152         writer.startLeafSetEntryNode(adapted);
153     }
154
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);
161         } else {
162             adapted = name;
163         }
164
165         writer.startMapEntryNode(adapted, size);
166     }
167
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;
171     }
172
173     private static final class AdapterCacheLoader extends CacheLoader<ListSchemaNode, NipAdapter> {
174         @Override
175         public NipAdapter load(final ListSchemaNode key) {
176             final Map<QName, ValueAdapter> adapters = new HashMap<>();
177
178             for (QName qname : key.getKeyDefinition()) {
179                 final DataSchemaNode child;
180                 try {
181                     child = key.findDataTreeChild(qname).orElseThrow();
182                 } catch (NoSuchElementException e) {
183                     throw new IllegalStateException("Failed to find child " + qname, e);
184                 }
185
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);
190                 }
191             }
192
193             return adapters.isEmpty() ? name -> name : new TransformingNipAdapter(adapters);
194         }
195     }
196
197     private static final class TransformingNipAdapter implements NipAdapter {
198         private final ImmutableMap<QName, ValueAdapter> adapters;
199
200         TransformingNipAdapter(final Map<QName, ValueAdapter> toTransform) {
201             adapters = ImmutableMap.copyOf(toTransform);
202         }
203
204         @Override
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());
212             }
213
214             return NodeIdentifierWithPredicates.of(name.getNodeType(), newEntries.build());
215         }
216     }
217 }