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.yangtools.yang.data.impl.schema.nodes;
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.Beta;
14 import java.util.Collection;
16 import java.util.Optional;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
21 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
22 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
24 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * Support utilities for dealing with Maps which would normally hold {@link DataContainerChild} values, but are modified
30 * to eliminate {@link LeafNode} instances.
33 * This class holds implementation logic which controls lifecycle of {@link LeafNode}s by providing a central policy
34 * point for how the implementation treats these nodes. There are two modes of operation:
36 * <li>eager, which means leaf nodes are retained by their parent<li>
37 * <li>lazy, which means leaf nodes are created whenever they are queried and no attempt is made to retain them</li>
41 * Selection of the mode in effect is available through {@value #EXPENDABLE_PROP_NAME} system property.
44 public final class LazyLeafOperations {
45 private static final Logger LOG = LoggerFactory.getLogger(LazyLeafOperations.class);
47 // FIXME: 6.0.0: remove this knob
48 private static final String EXPENDABLE_PROP_NAME =
49 "org.opendaylight.yangtools.yang.data.impl.schema.nodes.lazy-leaves";
52 * Global enabled run-time constant. If set to true, this class will treat {@link LeafNode} and
53 * {@link LeafSetEntryNode} as an expendable object. This constant is controlled by {@value #EXPENDABLE_PROP_NAME}
56 // FIXME: 6.0.0: remove this knob
57 private static final boolean EXPENDABLE;
60 EXPENDABLE = Boolean.parseBoolean(System.getProperty(EXPENDABLE_PROP_NAME, "true"));
62 LOG.warn("Leaf nodes are treated as regular nodes. This option is deprecated and is schedule for removal.");
66 private LazyLeafOperations() {
71 * A boolean flag indicating whether leaf nodes are being treated as expendable.
73 * @return True if NormalizedNode implementations in this artifact are treating leaf nodes as transient, i.e. do
76 // FIXME: 6.0.0: remove this method
77 public static boolean isEnabled() {
81 public static Optional<DataContainerChild<?, ?>> findChild(final Map<PathArgument, Object> map,
82 final PathArgument key) {
83 final Object value = map.get(key);
84 return value == null ? Optional.empty() : Optional.of(decodeChild(key, value));
87 public static @Nullable DataContainerChild<?, ?> getChild(final Map<PathArgument, Object> map,
88 final PathArgument key) {
89 final Object value = map.get(key);
90 return value == null ? null : decodeChild(key, value);
93 public static void putChild(final Map<PathArgument, Object> map, final DataContainerChild<?, ?> child) {
94 final DataContainerChild<?, ?> node = requireNonNull(child);
95 map.put(node.getIdentifier(), EXPENDABLE ? encodeExpendableChild(node) : node);
98 @SuppressWarnings({ "rawtypes", "unchecked" })
99 public static @NonNull Collection<DataContainerChild<?, ?>> getValue(final Map<PathArgument, Object> map) {
100 return EXPENDABLE ? new LazyValues(map)
101 // This is an ugly cast, but it is accurate IFF all modifications are done through this class
102 : (Collection)map.values();
105 static @NonNull LeafNode<?> coerceLeaf(final PathArgument key, final Object value) {
106 verify(key instanceof NodeIdentifier, "Unexpected value %s for child %s", value, key);
107 return ImmutableNodes.leafNode((NodeIdentifier) key, value);
110 private static @Nullable DataContainerChild<?, ?> decodeChild(final PathArgument key, final @NonNull Object value) {
111 return EXPENDABLE ? decodeExpendableChild(key, value) : verifyCast(value);
114 private static @NonNull DataContainerChild<?, ?> decodeExpendableChild(final PathArgument key,
115 @NonNull final Object value) {
116 return value instanceof DataContainerChild ? (DataContainerChild<?, ?>) value : coerceLeaf(key, value);
119 private static @NonNull Object encodeExpendableChild(final @NonNull DataContainerChild<?, ?> node) {
120 return node instanceof LeafNode ? verifyEncode(((LeafNode<?>) node).getValue()) : node;
123 private static @NonNull Object verifyEncode(final @NonNull Object value) {
124 verify(!(value instanceof DataContainerChild), "Unexpected leaf value %s", value);
128 private static @NonNull DataContainerChild<?, ?> verifyCast(final @NonNull Object value) {
129 verify(value instanceof DataContainerChild, "Unexpected child %s", value);
130 return (DataContainerChild<?, ?>)value;