2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.yangtools.yang.parser.impl;
11 import com.google.common.base.Preconditions;
13 import java.net.URISyntaxException;
14 import java.util.ArrayList;
15 import java.util.List;
16 import javax.xml.stream.XMLStreamConstants;
17 import javax.xml.stream.XMLStreamException;
18 import javax.xml.stream.XMLStreamReader;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.common.YangConstants;
21 import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
22 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
23 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
24 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
25 import org.opendaylight.yangtools.yang.parser.spi.source.DeclarationInTextSource;
26 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
27 import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
28 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
29 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
30 import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter;
31 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.TypeUtils;
32 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.Utils;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 public class YinStatementParserImpl {
38 private static final Logger LOG = LoggerFactory.getLogger(YinStatementParserImpl.class);
40 private final List<String> toBeSkipped = new ArrayList<>();
41 private final String sourceName;
42 private StatementWriter writer;
43 private QNameToStatementDefinition stmtDef;
44 private PrefixToModule prefixes;
45 private String uriStr;
46 private boolean isType = false;
47 private boolean action = true;
48 private boolean yinElement = false;
50 public YinStatementParserImpl(final String sourceName) {
51 this.sourceName = Preconditions.checkNotNull(sourceName);
56 * This method is supposed to be called in linkage phase, when YinStatementParserImpl instance has already been
58 * When done, start walking through YIN source
60 * @param writer - instance of StatementWriter to emit declared statements
61 * @param stmtDef - map of valid statement definitions for linkage phase
64 public void setAttributes(final StatementWriter writer, final QNameToStatementDefinition stmtDef) {
66 this.stmtDef = stmtDef;
70 * This method is supposed to be called in any phase but linkage, when YinStatementParserImpl instance has already
72 * When done, start walking through YIN source
74 * @param writer - instance of StatementWriter to emit declared statements
75 * @param stmtDef - map of valid statement definitions for any phase but linkage
76 * @param prefixes - map of valid prefixes for any phase but linkage
79 public void setAttributes(final StatementWriter writer, final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes) {
81 this.stmtDef = stmtDef;
82 this.prefixes = prefixes;
86 * This method executes parsing YIN source and emitting declared statements via attached StatementWriter
88 * @param inputReader - instance of XMlStreamReader, allows forward, read-only access to XML.
90 public void walk(final XMLStreamReader inputReader) {
92 while (inputReader.hasNext()) {
94 if (inputReader.hasName() && inputReader.getEventType() == XMLStreamConstants.START_ELEMENT) {
95 enterStatement(inputReader);
98 if (inputReader.hasName() && inputReader.getEventType() == XMLStreamConstants.END_ELEMENT) {
99 exitStatement(inputReader);
102 } catch (XMLStreamException e) {
103 LOG.warn("Fatal error detecting the next state of XMLStreamReader", e);
104 } catch (URISyntaxException e) {
105 LOG.warn("Given string {} violates RFC2396", uriStr, e);
109 private void startStatement(final QName identifier, final StatementSourceReference ref) {
110 writer.startStatement(identifier, ref);
113 private void argumentValue(final XMLStreamReader inputReader, final StatementSourceReference ref, final QName identifier, final boolean
116 writeTextOnlyElement(inputReader, ref);
118 writeNormalizedAttributeValue(inputReader, identifier, ref);
122 private void endStatement(final StatementSourceReference ref) {
123 writer.endStatement(ref);
126 private void enterStatement(final XMLStreamReader inputReader) throws URISyntaxException {
127 final StatementSourceReference ref = DeclarationInTextSource.atPosition(sourceName, inputReader
128 .getLocation().getLineNumber(), inputReader.getLocation().getColumnNumber());
129 uriStr = inputReader.getNamespaceURI();
130 final QName identifier = new QName(new URI(uriStr), getElementFullName(inputReader));
131 if (yinElement && toBeSkipped.isEmpty()) {
132 //at yin element, it has be read as argument
133 argumentValue(inputReader, ref, identifier, true);
135 if (isStatementWithYinElement(identifier, stmtDef)) {
136 //at statement with yin element, so next statement will be read as argument
140 final QName validStatementDefinition = Utils.getValidStatementDefinition(prefixes, stmtDef, identifier);
142 //main part -> valid statement for actual phase
143 if (stmtDef != null && validStatementDefinition != null && toBeSkipped.isEmpty()) {
144 if (identifier.equals(Rfc6020Mapping.TYPE.getStatementName())) {
147 startStatement(validStatementDefinition, ref);
148 if (isStatementWithYinElement(identifier, stmtDef)) {
153 //if statement not found through all phases, throw exception
154 SourceException.throwIf(writer.getPhase().equals(ModelProcessingPhase.FULL_DECLARATION), ref,
155 "%s is not a YIN statement or use of extension.", identifier.getLocalName());
157 //otherwise skip it (statement not to be read yet)
159 toBeSkipped.add(getElementFullName(inputReader));
163 writeTypeStmtAndArg(inputReader, identifier, ref);
164 } else if (action & isStatementWithArgument(identifier, stmtDef)) {
165 argumentValue(inputReader, ref, identifier, false);
172 private void exitStatement(final XMLStreamReader inputReader) throws URISyntaxException {
173 final String statementName = getElementFullName(inputReader);
174 final QName identifier = new QName(new URI(inputReader.getNamespaceURI()), statementName);
175 final StatementSourceReference ref = DeclarationInTextSource.atPosition(sourceName, inputReader
176 .getLocation().getLineNumber(), inputReader.getLocation().getColumnNumber());
177 final QName validStatementDefinition = Utils.getValidStatementDefinition(prefixes, stmtDef, identifier);
179 if ((stmtDef != null && validStatementDefinition != null && toBeSkipped.isEmpty()) && !yinElement) {
183 //back to normal mode
188 if (toBeSkipped.contains(statementName)) {
189 toBeSkipped.remove(statementName);
193 private void writeTextOnlyElement(final XMLStreamReader inputReader, final StatementSourceReference ref) {
195 writer.argumentValue(inputReader.getElementText(), ref);
196 } catch (XMLStreamException e) {
197 LOG.warn("Current event is not a START_ELEMENT or a non text element is encountered ", ref, e);
201 private void writeNormalizedAttributeValue(final XMLStreamReader inputReader, final QName
202 identifier, final StatementSourceReference ref) {
203 final String attributeValue = getAttributeValue(inputReader, identifier, stmtDef);
204 if (attributeValue != null) {
205 writer.argumentValue(attributeValue, ref);
209 private void writeTypeStmtAndArg(final XMLStreamReader inputReader, final QName identifier, final StatementSourceReference ref) {
210 String argument = getAttributeValue(inputReader, identifier, stmtDef);
211 if (TypeUtils.isYangTypeBodyStmtString(argument)) {
212 startStatement(new QName(YangConstants.RFC6020_YIN_NAMESPACE, argument), ref);
214 startStatement(new QName(YangConstants.RFC6020_YIN_NAMESPACE, Rfc6020Mapping
215 .TYPE.getStatementName().getLocalName()), ref);
217 argumentValue(inputReader, ref, identifier, false);
221 private static String getElementFullName(final XMLStreamReader inputReader) {
222 if (!inputReader.getPrefix().isEmpty()) {
223 return inputReader.getPrefix() + ":" + inputReader.getLocalName();
225 return inputReader.getLocalName();
229 private static boolean isStatementWithArgument(final QName identifier, final QNameToStatementDefinition stmtDef) {
230 if (stmtDef != null && stmtDef.get(Utils.trimPrefix(identifier)) == null) {
232 } else if (((StatementSupport<?, ?, ?>) stmtDef.get(Utils.trimPrefix(identifier))).getPublicView().getArgumentName() == null) {
238 private static boolean isStatementWithYinElement(final QName identifier, final QNameToStatementDefinition stmtDef) {
239 final StatementDefinition statementDefinition = stmtDef.get(Utils.trimPrefix(identifier));
240 if (statementDefinition == null) {
244 return ((Rfc6020Mapping) ((StatementSupport<?, ?, ?>) statementDefinition).getPublicView()).isArgumentYinElement();
247 private static String getAttributeValue(final XMLStreamReader inputReader, final QName identifier, final QNameToStatementDefinition
249 String namespace = null;
250 return inputReader.getAttributeValue(namespace, (((StatementSupport<?, ?, ?>) stmtDef.get(Utils.trimPrefix(identifier)))
251 .getPublicView()).getArgumentName().getLocalName());