2 * Copyright (c) 2021 PANTHEON.tech s.r.o. 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.spi.node;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.annotations.Beta;
13 import java.util.Base64;
14 import java.util.Iterator;
15 import java.util.Locale;
16 import java.util.Optional;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.yangtools.concepts.Immutable;
19 import org.opendaylight.yangtools.concepts.PrettyTree;
20 import org.opendaylight.yangtools.concepts.PrettyTreeAware;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.common.QNameModule;
23 import org.opendaylight.yangtools.yang.common.Revision;
24 import org.opendaylight.yangtools.yang.data.api.schema.ForeignDataNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
27 import org.opendaylight.yangtools.yang.data.api.schema.ValueNode;
30 public final class NormalizedNodePrettyTree extends PrettyTree implements Immutable {
31 private final @NonNull NormalizedNode node;
33 public NormalizedNodePrettyTree(final @NonNull NormalizedNode node) {
34 this.node = requireNonNull(node);
38 public void appendTo(final StringBuilder sb, final int depth) {
39 appendNode(sb, depth, null, node);
42 private static void appendNode(final StringBuilder sb, final int depth, final QNameModule parentNamespace,
43 final NormalizedNode node) {
44 final String simpleName = node.contract().getSimpleName();
45 appendIndent(sb, depth);
46 sb.append(simpleName.toLowerCase(Locale.ROOT).charAt(0)).append(simpleName, 1, simpleName.length()).append(' ');
48 final QName qname = node.name().getNodeType();
49 final QNameModule currentNamespace = qname.getModule();
50 appendNamespace(sb, parentNamespace, currentNamespace);
51 sb.append(qname.getLocalName()).append(' ');
53 if (node instanceof NormalizedNodeContainer) {
54 final NormalizedNodeContainer<?> container = (NormalizedNodeContainer<?>) node;
57 final Iterator<? extends NormalizedNode> it = container.body().iterator();
59 final int childIndent = depth + 1;
62 appendNode(sb, childIndent, currentNamespace, it.next());
63 } while (it.hasNext());
66 appendIndent(sb, depth);
69 } else if (node instanceof ValueNode) {
71 final Object value = node.body();
72 if (value instanceof byte[]) {
73 sb.append("(byte[])").append(Base64.getEncoder().encodeToString((byte[]) value));
74 } else if (value instanceof String) {
75 appendString(sb, (String) value);
79 } else if (node instanceof ForeignDataNode) {
80 final ForeignDataNode<?> data = (ForeignDataNode<?>) node;
81 final Object body = data.body();
82 if (body instanceof PrettyTreeAware) {
84 ((PrettyTreeAware) body).prettyTree().appendTo(sb, depth + 1);
85 appendIndent(sb, depth);
88 sb.append("= (").append(data.bodyObjectModel().getName()).append(')');
91 throw new IllegalStateException("Unhandled node " + node);
95 private static boolean appendNamespace(final StringBuilder sb, final QNameModule parent,
96 final QNameModule current) {
97 if (!current.equals(parent)) {
98 sb.append('(').append(current.getNamespace());
99 final Optional<Revision> rev = current.getRevision();
100 if (rev.isPresent()) {
101 sb.append('@').append(rev.orElseThrow());
109 private static void appendString(final StringBuilder sb, final String str) {
110 // TODO: do some escaping: '\r' '\n' '"' '\\' to make things even more zazzy
111 sb.append('"').append(str).append('"');