2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2024 Ericsson
4 * Modifications Copyright (C) 2024 OpenInfra Foundation Europe
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
21 package org.oran.smo.yangtools.parser.model.statements;
23 import java.lang.reflect.Constructor;
24 import java.util.HashMap;
27 import org.oran.smo.yangtools.parser.ParserExecutionContext;
28 import org.oran.smo.yangtools.parser.findings.Finding;
29 import org.oran.smo.yangtools.parser.findings.ParserFindingType;
30 import org.oran.smo.yangtools.parser.model.ModuleIdentity;
31 import org.oran.smo.yangtools.parser.model.statements.yang.YangCoreClassSupplier;
32 import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
33 import org.oran.smo.yangtools.parser.util.StackTraceHelper;
36 * Factory for creating instances of type-safe classes representing Yang statements.
38 * @author Mark Hollmann
40 public abstract class StatementFactory {
42 private static final Map<String, Constructor<? extends AbstractStatement>> CoreTypesConstructors = new HashMap<>();
44 private static final YangCoreClassSupplier yangCoreClassSupplier = new YangCoreClassSupplier();
47 * Creates an instance of a core Yang statement.
49 @SuppressWarnings("unchecked")
50 public static <T extends AbstractStatement> T createYangCoreStatement(final ParserExecutionContext context,
51 final YangDomElement domElement, final AbstractStatement parentStatement) {
53 final String yangStatementName = domElement.getName();
55 if (!CoreTypesConstructors.containsKey(yangStatementName)) {
56 final Class<? extends AbstractStatement> clazz = yangCoreClassSupplier.getJavaClazzForStatement(null,
58 final Constructor<? extends AbstractStatement> constructor = clazz.getConstructor(AbstractStatement.class,
59 YangDomElement.class);
60 CoreTypesConstructors.put(yangStatementName, constructor);
63 final Constructor<? extends AbstractStatement> constructor = CoreTypesConstructors.get(yangStatementName);
64 final AbstractStatement newInstance = constructor.newInstance(parentStatement, domElement);
66 return (T) newInstance;
68 } catch (final Exception ex) {
69 context.addFinding(new Finding(domElement, ParserFindingType.P015_INVALID_SYNTAX_IN_DOCUMENT.toString(),
70 "Not a valid YANG statement: " + yangStatementName));
77 * Creates an instance of an extension statement.
79 @SuppressWarnings("unchecked")
80 public static <T extends ExtensionStatement> T createYangExtensionStatement(final ParserExecutionContext context,
81 final YangDomElement domNode, final AbstractStatement parentStatement) {
83 final String[] prefixAndStatement = domNode.getName().split(":");
84 final String prefix = prefixAndStatement[0];
85 final String extStatementName = prefixAndStatement[1];
87 final ModuleIdentity moduleIdentity = parentStatement.getPrefixResolver().getModuleForPrefix(prefix);
88 if (moduleIdentity == null) {
89 context.addFinding(new Finding(domNode, ParserFindingType.P033_UNRESOLVEABLE_PREFIX.toString(),
90 "Prefix '" + prefixAndStatement[0] + "' for the extension statement not resolvable."));
94 final String extModuleName = moduleIdentity.getModuleName();
97 final Class<? extends ExtensionStatement> clazz = getClassForYangExtension(context, extModuleName,
99 final Constructor<? extends ExtensionStatement> constructor = clazz.getConstructor(AbstractStatement.class,
100 YangDomElement.class);
102 final ExtensionStatement newInstance = constructor.newInstance(parentStatement, domNode);
104 return (T) newInstance;
105 } catch (final NoSuchMethodException nsmex) {
106 context.addFinding(new Finding(domNode, ParserFindingType.P002_INVALID_EXTENSION_STATEMENT_CLASS.toString(),
107 "Extension statement class constructor wrong."));
108 } catch (final Exception ex) {
109 context.addFinding(new Finding(domNode, ParserFindingType.P000_UNSPECIFIED_ERROR.toString(),
110 "During instantiation of extension statement: " + ex.getMessage() + " - trace: " + StackTraceHelper
111 .getStackTraceInfo(ex)));
117 @SuppressWarnings("unchecked")
118 public static <T extends AbstractStatement> T cloneYangStatement(final T statementToClone,
119 final AbstractStatement parentOfClone) {
121 final YangDomElement domElementOfStatementToClone = statementToClone.getDomElement();
122 final Class<? extends AbstractStatement> clazz = statementToClone.getClass();
125 final Constructor<? extends AbstractStatement> constructor = clazz.getConstructor(AbstractStatement.class,
126 YangDomElement.class);
127 final AbstractStatement newInstance = constructor.newInstance(parentOfClone, domElementOfStatementToClone);
129 return (T) newInstance;
131 } catch (final Exception ex) {
132 // no-op, cannot happen
138 * Given the module name where an extension is defined, and the extension name, returns either a dedicated
139 * class that can handle the statement, or the catch-all {@link ExtensionStatement} class.
141 @SuppressWarnings("unchecked")
142 private static <T extends ExtensionStatement> Class<T> getClassForYangExtension(final ParserExecutionContext context,
143 final String moduleName, final String statementName) {
145 for (final StatementClassSupplier supplier : context.getExtensionCreators()) {
146 final Class<ExtensionStatement> extensionClazz = supplier.getJavaClazzForStatement(moduleName, statementName);
147 if (extensionClazz != null) {
148 return (Class<T>) extensionClazz;
153 * No supplier found that can handle the extensions, we return extension catch-all base class.
155 return (Class<T>) ExtensionStatement.class;