Bug 5200: Yang parser doesn't fill error-app-tag and error-message in constraints
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / spi / meta / StmtContextUtils.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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.parser.spi.meta;
9
10 import com.google.common.base.Function;
11 import com.google.common.base.Splitter;
12 import com.google.common.collect.ImmutableList;
13 import com.google.common.collect.ImmutableSet;
14 import com.google.common.collect.ImmutableSet.Builder;
15 import java.util.Collection;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.common.QNameModule;
18 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
19 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
20 import org.opendaylight.yangtools.yang.model.api.stmt.KeyStatement;
21 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
22 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.UnknownStatementImpl;
23
24 public final class StmtContextUtils {
25     public static final Splitter LIST_KEY_SPLITTER = Splitter.on(' ').omitEmptyStrings().trimResults();
26
27     private static final Function<StmtContext<?, ?,?>, DeclaredStatement<?>> BUILD_DECLARED =
28             new Function<StmtContext<?,?,?>, DeclaredStatement<?>>() {
29         @Override
30         public DeclaredStatement<?> apply(final StmtContext<?, ?, ?> input) {
31             return input.buildDeclared();
32         }
33     };
34
35     private static final Function<StmtContext<?, ?,?>, EffectiveStatement<?,?>> BUILD_EFFECTIVE =
36             new Function<StmtContext<?,?,?>, EffectiveStatement<?,?>>() {
37         @Override
38         public EffectiveStatement<?, ?> apply(final StmtContext<?, ?, ?> input) {
39             return input.buildEffective();
40         }
41     };
42
43     private StmtContextUtils() {
44         throw new UnsupportedOperationException("Utility class");
45     }
46
47     @SuppressWarnings("unchecked")
48     public static <D extends DeclaredStatement<?>> Function<StmtContext<?, ? extends D, ?>, D> buildDeclared() {
49         return Function.class.cast(BUILD_DECLARED);
50     }
51
52     @SuppressWarnings("unchecked")
53     public static <E extends EffectiveStatement<?, ?>> Function<StmtContext<?, ?, ? extends E>, E> buildEffective() {
54         return Function.class.cast(BUILD_EFFECTIVE);
55     }
56
57     @SuppressWarnings("unchecked")
58     public static <AT, DT extends DeclaredStatement<AT>> AT firstAttributeOf(
59             final Iterable<? extends StmtContext<?, ?, ?>> contexts, final Class<DT> declaredType) {
60         for (StmtContext<?, ?, ?> ctx : contexts) {
61             if (producesDeclared(ctx, declaredType)) {
62                 return (AT) ctx.getStatementArgument();
63             }
64         }
65         return null;
66     }
67
68     @SuppressWarnings("unchecked")
69     public static <AT, DT extends DeclaredStatement<AT>> AT firstAttributeOf(final StmtContext<?, ?, ?> ctx,
70             final Class<DT> declaredType) {
71         return producesDeclared(ctx, declaredType) ? (AT) ctx.getStatementArgument() : null;
72     }
73
74     public static <AT, DT extends DeclaredStatement<AT>> AT firstSubstatementAttributeOf(
75             final StmtContext<?, ?, ?> ctx, final Class<DT> declaredType) {
76         AT firstAttribute = firstAttributeOf(ctx.effectiveSubstatements(), declaredType);
77         return firstAttribute != null ? firstAttribute : firstAttributeOf(ctx.declaredSubstatements(), declaredType);
78     }
79
80     @SuppressWarnings("unchecked")
81     public static <AT,DT extends DeclaredStatement<AT>> StmtContext<AT, ?, ?> findFirstDeclaredSubstatement(
82             final StmtContext<?, ?, ?> stmtContext, final Class<DT> declaredType) {
83         for (StmtContext<?, ?, ?> subStmtContext : stmtContext.declaredSubstatements()) {
84             if (producesDeclared(subStmtContext,declaredType)) {
85                 return (StmtContext<AT, ?, ?>) subStmtContext;
86             }
87         }
88         return null;
89     }
90
91     @SuppressWarnings("unchecked")
92     public static <AT, DT extends DeclaredStatement<AT>> Collection<StmtContext<AT, DT, ?>> findAllDeclaredSubstatements(
93             final StmtContext<?, ?, ?> stmtContext, final Class<DT> declaredType) {
94         ImmutableList.Builder<StmtContext<AT, DT, ?>> listBuilder = ImmutableList.builder();
95         for (StmtContext<?, ?, ?> subStmtContext : stmtContext.declaredSubstatements()) {
96             if (producesDeclared(subStmtContext, declaredType)) {
97                 listBuilder.add((StmtContext<AT, DT, ?>) subStmtContext);
98             }
99         }
100         return listBuilder.build();
101     }
102
103     @SuppressWarnings("unchecked")
104     public static <AT, DT extends DeclaredStatement<AT>> Collection<StmtContext<AT, DT, ?>> findAllEffectiveSubstatements(
105             final StmtContext<?, ?, ?> stmtContext, final Class<DT> type) {
106         ImmutableList.Builder<StmtContext<AT, DT, ?>> listBuilder = ImmutableList.builder();
107         for (StmtContext<?, ?, ?> subStmtContext : stmtContext.effectiveSubstatements()) {
108             if (producesDeclared(subStmtContext, type)) {
109                 listBuilder.add((StmtContext<AT, DT, ?>) subStmtContext);
110             }
111         }
112         return listBuilder.build();
113     }
114
115     public static <AT, DT extends DeclaredStatement<AT>> Collection<StmtContext<AT, DT, ?>> findAllSubstatements(
116             final StmtContext<?, ?, ?> stmtContext, final Class<DT> type) {
117         ImmutableList.Builder<StmtContext<AT, DT, ?>> listBuilder = ImmutableList.builder();
118         listBuilder.addAll(findAllDeclaredSubstatements(stmtContext, type));
119         listBuilder.addAll(findAllEffectiveSubstatements(stmtContext, type));
120         return listBuilder.build();
121     }
122
123     @SuppressWarnings("unchecked")
124     public static <AT,DT extends DeclaredStatement<AT>> StmtContext<AT, ?, ?> findFirstEffectiveSubstatement(
125             final StmtContext<?, ?, ?> stmtContext, final Class<DT> declaredType) {
126         for (StmtContext<?, ?, ?> subStmtContext : stmtContext.effectiveSubstatements()) {
127             if (producesDeclared(subStmtContext,declaredType)) {
128                 return (StmtContext<AT, ?, ?>) subStmtContext;
129             }
130         }
131         return null;
132     }
133
134     public static <AT,DT extends DeclaredStatement<AT>> StmtContext<AT, ?, ?> findFirstSubstatement(
135             final StmtContext<?, ?, ?> stmtContext, final Class<DT> declaredType) {
136         StmtContext<AT, ?, ?> declaredSubstatement = findFirstDeclaredSubstatement(stmtContext, declaredType);
137         return declaredSubstatement != null ? declaredSubstatement : findFirstEffectiveSubstatement(stmtContext, declaredType);
138     }
139
140     @SafeVarargs
141     public static StmtContext<?, ?, ?> findFirstDeclaredSubstatement(final StmtContext<?, ?, ?> stmtContext,
142             int startIndex, final Class<? extends DeclaredStatement<?>>... types) {
143         if (startIndex >= types.length) {
144             return null;
145         }
146
147         for (StmtContext<?, ?, ?> subStmtContext : stmtContext.declaredSubstatements()) {
148             if (producesDeclared(subStmtContext,types[startIndex])) {
149                 return startIndex + 1 == types.length ? subStmtContext
150                         : findFirstDeclaredSubstatement(subStmtContext, ++startIndex, types);
151             }
152         }
153         return null;
154     }
155
156     public static <DT extends DeclaredStatement<?>> StmtContext<?, ?, ?> findFirstDeclaredSubstatementOnSublevel(
157             final StmtContext<?, ?, ?> stmtContext, final Class<DT> declaredType, int sublevel) {
158         for (StmtContext<?, ?, ?> subStmtContext : stmtContext.declaredSubstatements()) {
159             if (sublevel == 1 && producesDeclared(subStmtContext, declaredType)) {
160                 return subStmtContext;
161             }
162             if (sublevel > 1) {
163                 final StmtContext<?, ?, ?> result = findFirstDeclaredSubstatementOnSublevel(
164                     subStmtContext, declaredType, --sublevel);
165                 if (result != null) {
166                     return result;
167                 }
168             }
169         }
170
171         return null;
172     }
173
174     public static <DT extends DeclaredStatement<?>> StmtContext<?, ?, ?> findDeepFirstDeclaredSubstatement(
175             final StmtContext<?, ?, ?> stmtContext, final Class<DT> declaredType) {
176         for (StmtContext<?, ?, ?> subStmtContext : stmtContext.declaredSubstatements()) {
177             if (producesDeclared(subStmtContext, declaredType)) {
178                 return subStmtContext;
179             }
180
181             final StmtContext<?, ?, ?> result = findDeepFirstDeclaredSubstatement(subStmtContext, declaredType);
182             if (result != null) {
183                 return result;
184             }
185         }
186
187         return null;
188     }
189
190     public static boolean producesDeclared(final StmtContext<?, ?, ?> ctx,
191             final Class<? extends DeclaredStatement<?>> type) {
192         return type.isAssignableFrom(ctx.getPublicDefinition().getDeclaredRepresentationClass());
193     }
194
195     public static boolean isInExtensionBody(final StmtContext<?,?,?> stmtCtx) {
196         StmtContext<?,?,?> current = stmtCtx;
197         while (!current.getParentContext().isRootContext()) {
198             current = current.getParentContext();
199             if (producesDeclared(current, UnknownStatementImpl.class)) {
200                 return true;
201             }
202         }
203
204         return false;
205     }
206
207     public static boolean isUnknownStatement(final StmtContext<?, ?, ?> stmtCtx) {
208         return producesDeclared(stmtCtx, UnknownStatementImpl.class);
209     }
210
211     public static Collection<SchemaNodeIdentifier> replaceModuleQNameForKey(
212             final StmtContext<Collection<SchemaNodeIdentifier>, KeyStatement, ?> keyStmtCtx,
213             final QNameModule newQNameModule) {
214
215         final Builder<SchemaNodeIdentifier> builder = ImmutableSet.builder();
216         boolean replaced = false;
217         for (SchemaNodeIdentifier arg : keyStmtCtx.getStatementArgument()) {
218             final QName qname = arg.getLastComponent();
219             if (!newQNameModule.equals(qname)) {
220                 final QName newQname = keyStmtCtx.getFromNamespace(QNameCacheNamespace.class,
221                     QName.create(newQNameModule, qname.getLocalName()));
222                 builder.add(SchemaNodeIdentifier.create(false, newQname));
223                 replaced = true;
224             } else {
225                 builder.add(arg);
226             }
227         }
228
229         // This makes sure we reuse the collection when a grouping is instantiated in the same module
230         return replaced ? builder.build() : keyStmtCtx.getStatementArgument();
231     }
232 }