Instantiate a QName cache
[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.Predicate;
12 import com.google.common.base.Splitter;
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     public static final Predicate<StmtContext<?, ?,?>> IS_SUPPORTED_TO_BUILD_EFFECTIVE =
44             new Predicate<StmtContext<?,?,?>>() {
45         @Override
46         public boolean apply(final StmtContext<?, ?, ?> input) {
47             return input.isSupportedToBuildEffective();
48         }
49     };
50
51     private StmtContextUtils() {
52         throw new UnsupportedOperationException("Utility class");
53     }
54
55     @SuppressWarnings("unchecked")
56     public static <D extends DeclaredStatement<?>> Function<StmtContext<?, ? extends D, ?>, D> buildDeclared() {
57         return Function.class.cast(BUILD_DECLARED);
58     }
59
60     @SuppressWarnings("unchecked")
61     public static <E extends EffectiveStatement<?, ?>> Function<StmtContext<?, ?, ? extends E>, E> buildEffective() {
62         return Function.class.cast(BUILD_EFFECTIVE);
63     }
64
65     @SuppressWarnings("unchecked")
66     public static <AT, DT extends DeclaredStatement<AT>> AT firstAttributeOf(
67             final Iterable<? extends StmtContext<?, ?, ?>> contexts, final Class<DT> declaredType) {
68         for (StmtContext<?, ?, ?> ctx : contexts) {
69             if (producesDeclared(ctx, declaredType)) {
70                 return (AT) ctx.getStatementArgument();
71             }
72         }
73         return null;
74     }
75
76     @SuppressWarnings("unchecked")
77     public static <AT, DT extends DeclaredStatement<AT>> AT firstAttributeOf(final StmtContext<?, ?, ?> ctx,
78             final Class<DT> declaredType) {
79         return producesDeclared(ctx, declaredType) ? (AT) ctx.getStatementArgument() : null;
80     }
81
82     @SuppressWarnings("unchecked")
83     public static <AT,DT extends DeclaredStatement<AT>> StmtContext<AT, ?, ?> findFirstDeclaredSubstatement(
84             final StmtContext<?, ?, ?> stmtContext, final Class<DT> declaredType) {
85         for (StmtContext<?, ?, ?> subStmtContext : stmtContext.declaredSubstatements()) {
86             if (producesDeclared(subStmtContext,declaredType)) {
87                 return (StmtContext<AT, ?, ?>) subStmtContext;
88             }
89         }
90         return null;
91     }
92
93     @SafeVarargs
94     public static StmtContext<?, ?, ?> findFirstDeclaredSubstatement(final StmtContext<?, ?, ?> stmtContext,
95             int startIndex, final Class<? extends DeclaredStatement<?>>... types) {
96         if (startIndex >= types.length) {
97             return null;
98         }
99
100         for (StmtContext<?, ?, ?> subStmtContext : stmtContext.declaredSubstatements()) {
101             if (producesDeclared(subStmtContext,types[startIndex])) {
102                 return startIndex + 1 == types.length ? subStmtContext
103                         : findFirstDeclaredSubstatement(subStmtContext, ++startIndex, types);
104             }
105         }
106         return null;
107     }
108
109     public static <DT extends DeclaredStatement<?>> StmtContext<?, ?, ?> findFirstDeclaredSubstatementOnSublevel(
110             final StmtContext<?, ?, ?> stmtContext, final Class<DT> declaredType, int sublevel) {
111         for (StmtContext<?, ?, ?> subStmtContext : stmtContext.declaredSubstatements()) {
112             if (sublevel == 1 && producesDeclared(subStmtContext, declaredType)) {
113                 return subStmtContext;
114             }
115             if (sublevel > 1) {
116                 final StmtContext<?, ?, ?> result = findFirstDeclaredSubstatementOnSublevel(
117                     subStmtContext, declaredType, --sublevel);
118                 if (result != null) {
119                     return result;
120                 }
121             }
122         }
123
124         return null;
125     }
126
127     public static <DT extends DeclaredStatement<?>> StmtContext<?, ?, ?> findDeepFirstDeclaredSubstatement(
128             final StmtContext<?, ?, ?> stmtContext, final Class<DT> declaredType) {
129         for (StmtContext<?, ?, ?> subStmtContext : stmtContext.declaredSubstatements()) {
130             if (producesDeclared(subStmtContext, declaredType)) {
131                 return subStmtContext;
132             }
133
134             final StmtContext<?, ?, ?> result = findDeepFirstDeclaredSubstatement(subStmtContext, declaredType);
135             if (result != null) {
136                 return result;
137             }
138         }
139
140         return null;
141     }
142
143     public static boolean producesDeclared(final StmtContext<?, ?, ?> ctx,
144             final Class<? extends DeclaredStatement<?>> type) {
145         return type.isAssignableFrom(ctx.getPublicDefinition().getDeclaredRepresentationClass());
146     }
147
148     public static boolean isInExtensionBody(final StmtContext<?,?,?> stmtCtx) {
149         StmtContext<?,?,?> current = stmtCtx;
150         while (!current.getParentContext().isRootContext()) {
151             current = current.getParentContext();
152             if (producesDeclared(current, UnknownStatementImpl.class)) {
153                 return true;
154             }
155         }
156
157         return false;
158     }
159
160     public static boolean isUnknownStatement(final StmtContext<?, ?, ?> stmtCtx) {
161         return producesDeclared(stmtCtx, UnknownStatementImpl.class);
162     }
163
164     public static Collection<SchemaNodeIdentifier> replaceModuleQNameForKey(
165             final StmtContext<Collection<SchemaNodeIdentifier>, KeyStatement, ?> keyStmtCtx,
166             final QNameModule newQNameModule) {
167
168         final Builder<SchemaNodeIdentifier> builder = ImmutableSet.builder();
169         boolean replaced = false;
170         for (SchemaNodeIdentifier arg : keyStmtCtx.getStatementArgument()) {
171             final QName qname = arg.getLastComponent();
172             if (!newQNameModule.equals(qname)) {
173                 final QName newQname = keyStmtCtx.getFromNamespace(QNameCacheNamespace.class,
174                     QName.create(newQNameModule, qname.getLocalName()));
175                 builder.add(SchemaNodeIdentifier.create(false, newQname));
176                 replaced = true;
177             } else {
178                 builder.add(arg);
179             }
180         }
181
182         // This makes sure we reuse the collection when a grouping is instantiated in the same module
183         return replaced ? builder.build() : keyStmtCtx.getStatementArgument();
184     }
185 }