Populate data/ hierarchy
[yangtools.git] / data / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / ImmutableMetadataNormalizedNodeStreamWriter.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.yangtools.yang.data.impl.schema;
9
10 import static com.google.common.base.Preconditions.checkState;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.annotations.Beta;
14 import com.google.common.collect.ClassToInstanceMap;
15 import com.google.common.collect.ImmutableClassToInstanceMap;
16 import com.google.common.collect.ImmutableMap;
17 import java.io.IOException;
18 import java.util.ArrayDeque;
19 import java.util.Deque;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.yangtools.rfc7952.data.api.NormalizedMetadata;
22 import org.opendaylight.yangtools.rfc7952.data.api.StreamWriterMetadataExtension;
23 import org.opendaylight.yangtools.rfc7952.data.util.ImmutableNormalizedMetadata;
24 import org.opendaylight.yangtools.rfc7952.data.util.ImmutableNormalizedMetadata.Builder;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
27 import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder;
28 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriterExtension;
29
30 /**
31  * A {@link NormalizedMetadata}-aware {@link ImmutableMetadataNormalizedNodeStreamWriter}. It advertizes the
32  * {@link StreamWriterMetadataExtension} extension.
33  */
34 @Beta
35 public class ImmutableMetadataNormalizedNodeStreamWriter extends ImmutableNormalizedNodeStreamWriter
36         implements StreamWriterMetadataExtension {
37     /**
38      * Snapshot of currently-open data- and metadatastate.
39      */
40     public static final class State {
41         final Builder metaBuilder;
42         final NormalizedNodeBuilder dataBuilder;
43
44         State(final NormalizedNodeBuilder dataBuilder, final Builder metadataBuilder) {
45             this.dataBuilder = requireNonNull(dataBuilder);
46             this.metaBuilder = requireNonNull(metadataBuilder);
47         }
48
49         public NormalizedNodeBuilder getDataBuilder() {
50             return dataBuilder;
51         }
52
53         public Builder getMetaBuilder() {
54             return metaBuilder;
55         }
56     }
57
58     private final Deque<Builder> builders = new ArrayDeque<>();
59     private final NormalizedNodeMetadataResult result;
60
61     protected ImmutableMetadataNormalizedNodeStreamWriter(final State state) {
62         super(state.getDataBuilder());
63         builders.push(state.getMetaBuilder());
64         result = null;
65     }
66
67     protected ImmutableMetadataNormalizedNodeStreamWriter(final NormalizedNodeMetadataResult result) {
68         super(result);
69         this.result = requireNonNull(result);
70     }
71
72     @Override
73     public final ClassToInstanceMap<NormalizedNodeStreamWriterExtension> getExtensions() {
74         return ImmutableClassToInstanceMap.of(StreamWriterMetadataExtension.class, this);
75     }
76
77     @Override
78     public final void metadata(final ImmutableMap<QName, Object> metadata) throws IOException {
79         final Builder current = builders.peek();
80         checkState(current != null, "Attempted to emit metadata when no metadata is open");
81         current.withAnnotations(metadata);
82     }
83
84     /**
85      * Remove the currently-open builders for data and metadata from the stack.
86      *
87      * @return Builder state.
88      */
89     protected final @NonNull State popState() {
90         return new State(popBuilder(), builders.pop());
91     }
92
93     @Override
94     @SuppressWarnings("rawtypes")
95     final void enter(final PathArgument identifier, final NormalizedNodeBuilder next) {
96         super.enter(identifier, next);
97         builders.push(ImmutableNormalizedMetadata.builder().withIdentifier(identifier));
98     }
99
100     @Override
101     public final void endNode() {
102         super.endNode();
103         final ImmutableNormalizedMetadata metadata = builders.pop().build();
104         final Builder current = builders.peek();
105         if (current != null) {
106             if (!metadata.getAnnotations().isEmpty() || !metadata.getChildren().isEmpty()) {
107                 current.withChild(metadata);
108             }
109         } else {
110             // All done
111             result.setResult(metadata);
112         }
113     }
114 }