Add YangTextSnippet to yang-model-export
[yangtools.git] / yang / yang-model-export / src / main / java / org / opendaylight / yangtools / yang / model / export / YangTextSnippet.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, 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.model.export;
9
10 import static java.util.Objects.requireNonNull;
11 import static org.eclipse.jdt.annotation.DefaultLocation.PARAMETER;
12 import static org.eclipse.jdt.annotation.DefaultLocation.RETURN_TYPE;
13
14 import com.google.common.annotations.Beta;
15 import com.google.common.collect.ImmutableSet;
16 import java.util.ArrayList;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21 import java.util.Spliterator;
22 import java.util.Spliterators;
23 import java.util.stream.Collectors;
24 import java.util.stream.Stream;
25 import java.util.stream.StreamSupport;
26 import javax.annotation.concurrent.ThreadSafe;
27 import org.eclipse.jdt.annotation.NonNull;
28 import org.eclipse.jdt.annotation.NonNullByDefault;
29 import org.opendaylight.yangtools.concepts.Immutable;
30 import org.opendaylight.yangtools.yang.common.QNameModule;
31 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
32 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
33 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
34 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement.QNameModuleToPrefixNamespace;
35
36 /**
37  * A YANG text snippet generated from a {@link DeclaredStatement}. Generated {@link #stream()} or {@link #iterator()}
38  * are guaranteed to not contain null nor empty strings. Furthermore, newlines are always emitted at the end
39  * on the generated string -- which can be checked with {@link #isEolString(String)} utility method.
40  *
41  * <p>
42  * This allows individual strings to be escaped as needed and external indentation can be accounted for by inserting
43  * outer document indentation after the string which matched {@link #isEolString(String)} is emitted to the stream.
44  *
45  * @author Robert Varga
46  */
47 @Beta
48 @ThreadSafe
49 @NonNullByDefault({ PARAMETER, RETURN_TYPE })
50 public final class YangTextSnippet implements Immutable, Iterable<@NonNull String> {
51     private final Set<@NonNull StatementDefinition> ignoredStatements;
52     private final Map<QNameModule, @NonNull String> mapper;
53     private final DeclaredStatement<?> statement;
54     private final boolean omitDefaultStatements;
55
56     private YangTextSnippet(final DeclaredStatement<?> statement,
57             final Map<QNameModule, @NonNull String> namespaces,
58             final Set<@NonNull StatementDefinition> ignoredStatements, final boolean omitDefaultStatements) {
59         this.statement = requireNonNull(statement);
60         this.mapper = requireNonNull(namespaces);
61         this.ignoredStatements = requireNonNull(ignoredStatements);
62         this.omitDefaultStatements = omitDefaultStatements;
63     }
64
65     public static Builder builder(final ModuleEffectiveStatement module, final DeclaredStatement<?> statement) {
66         return new Builder(module, statement);
67     }
68
69     @Override
70     public Iterator<@NonNull String> iterator() {
71         return new YangTextSnippetIterator(statement, mapper, ignoredStatements, omitDefaultStatements);
72     }
73
74     @Override
75     @SuppressWarnings("null")
76     public Spliterator<@NonNull String> spliterator() {
77         return Spliterators.spliteratorUnknownSize(iterator(),
78             Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL);
79     }
80
81     @SuppressWarnings("null")
82     public Stream<@NonNull String> stream() {
83         return StreamSupport.stream(spliterator(), false);
84     }
85
86     /**
87      * Check if an emitted string contains End-Of-Line character.
88      *
89      * @param str String to be checked
90      * @return True if the string contains end of line.
91      */
92     public static boolean isEolString(final String str) {
93         return str.charAt(str.length() - 1) == '\n';
94     }
95
96     @Override
97     @SuppressWarnings("null")
98     public String toString() {
99         return stream().collect(Collectors.joining());
100     }
101
102     /**
103      * Builder class for instantiation of a customized {@link YangTextSnippet}.
104      */
105     @Beta
106     public static final class Builder implements org.opendaylight.yangtools.concepts.Builder<@NonNull YangTextSnippet> {
107         private final List<@NonNull StatementDefinition> ignoredStatements = new ArrayList<>();
108         private final @NonNull DeclaredStatement<?> statement;
109         private final @NonNull ModuleEffectiveStatement module;
110         private boolean retainDefaultStatements;
111
112         Builder(final ModuleEffectiveStatement module, final DeclaredStatement<?> statement) {
113             this.module = requireNonNull(module);
114             this.statement = requireNonNull(statement);
115         }
116
117         /**
118          * Add a statement which should be skipped along with any of its children.
119          *
120          * @param statementDef Statement to be ignored
121          * @return This builder
122          */
123         public Builder addIgnoredStatement(final StatementDefinition statementDef) {
124             ignoredStatements.add(requireNonNull(statementDef));
125             return this;
126         }
127
128         /**
129          * Retain common known statements whose argument matches semantics of not being present. By default these
130          * statements are omitted from output.
131          *
132          * @return This builder
133          */
134         public Builder retainDefaultStatements() {
135             retainDefaultStatements = true;
136             return this;
137         }
138
139         @Override
140         public YangTextSnippet build() {
141             return new YangTextSnippet(statement, module.getAll(QNameModuleToPrefixNamespace.class),
142                 ImmutableSet.copyOf(ignoredStatements), !retainDefaultStatements);
143         }
144     }
145 }