org.opendaylight.yangtools.yang.model.export.SingleModuleYinStatementWriter.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.yangtools.yang.model.export.SingleModuleYinStatementWriter.java

Source

/*
 * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.yangtools.yang.model.export;

import com.google.common.annotations.Beta;
import com.google.common.base.Preconditions;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import java.net.URI;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import javax.xml.XMLConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.YangConstants;
import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;

@Beta
@NotThreadSafe
class SingleModuleYinStatementWriter implements StatementTextWriter {

    private final XMLStreamWriter writer;
    private final URI currentModuleNs;
    private final BiMap<String, URI> prefixToNamespace;
    private StatementDefinition currentStatement;

    private SingleModuleYinStatementWriter(final XMLStreamWriter writer, final URI moduleNamespace,
            final Map<String, URI> prefixToNs) {
        super();
        this.writer = writer;
        this.currentModuleNs = moduleNamespace;
        this.prefixToNamespace = HashBiMap.create(prefixToNs);
        initializeYinNamespaceInXml();
    }

    private void initializeYinNamespaceInXml() {
        try {
            final String defaultNs = writer.getNamespaceContext().getNamespaceURI(XMLConstants.NULL_NS_URI);
            if (defaultNs == null) {
                writer.setDefaultNamespace(YangConstants.RFC6020_YIN_NAMESPACE.toString());
            } else if (!YangConstants.RFC6020_YIN_NAMESPACE.toString().equals(defaultNs)) {
                // FIXME: Implement support for exporting YIN as part of other XML document.
                throw new UnsupportedOperationException(
                        "Not implemented support for nesting YIN in different XML element.");
            }
        } catch (final XMLStreamException e) {
            throw new IllegalStateException(e);
        }
    }

    static StatementTextWriter create(final XMLStreamWriter writer, final URI moduleNs,
            final Map<String, URI> prefixToNs) {
        return new SingleModuleYinStatementWriter(writer, moduleNs, prefixToNs);
    }

    @Override
    public void startStatement(final StatementDefinition statement) {
        currentStatement = Preconditions.checkNotNull(statement);
        try {
            writeStartXmlElement(statement.getStatementName());
            if (YangStmtMapping.MODULE.equals(statement) || YangStmtMapping.SUBMODULE.equals(statement)) {
                declareXmlNamespaces(prefixToNamespace);
            }
        } catch (final XMLStreamException e) {
            // FIXME: Introduce proper expression
            throw new IllegalStateException(e);
        }
    }

    @Override
    public void endStatement() {
        currentStatement = null;
        try {
            writeXmlEndElement();
        } catch (final XMLStreamException e) {
            // FIXME: Introduce proper expression
            throw new IllegalStateException(e);
        }
    }

    @Override
    public void writeArgument(final String strRep) {
        checkArgumentApplicable();
        writeArgument0(strRep);
    }

    @Override
    public void writeArgument(final QName value) {
        checkArgumentApplicable();
        final String valueStr = toPrefixedString(value);
        writeArgument0(valueStr);
    }

    @Override
    public void writeArgument(final SchemaPath targetPath) {
        checkArgumentApplicable();
        final StringBuilder valueStr = new StringBuilder();
        if (targetPath.isAbsolute()) {
            valueStr.append("/");
        }
        final Iterator<QName> argIt = targetPath.getPathFromRoot().iterator();
        while (argIt.hasNext()) {
            valueStr.append(toPrefixedString(argIt.next()));
            if (argIt.hasNext()) {
                valueStr.append("/");
            }
        }
        writeArgument0(valueStr.toString());
    }

    @Override
    public void writeArgument(final RevisionAwareXPath xpath) {
        checkArgumentApplicable();
        // FIXME: This implementation assumes prefixes are unchanged
        // and were not changed in schema context.
        writeArgument0(xpath.toString());
    }

    private void writeArgument0(final String strRep) {
        try {
            if (isArgumentYinElement(currentStatement)) {
                writeStartXmlElement(currentStatement.getArgumentName());
                writeXmlText(strRep);
                writeXmlEndElement();
            } else {
                writeXmlArgument(currentStatement.getArgumentName(), strRep);
            }
        } catch (final XMLStreamException e) {
            // FIXME: throw proper exception
            throw new IllegalStateException(e);
        }
    }

    private static boolean isArgumentYinElement(final StatementDefinition currentStatement) {
        if (currentStatement instanceof YangStmtMapping || currentStatement instanceof ExtensionStatement) {
            return currentStatement.isArgumentYinElement();
        }
        return false;
    }

    private void checkArgumentApplicable() {
        Preconditions.checkState(currentStatement != null, "No statement is opened.");
        Preconditions.checkState(currentStatement.getArgumentName() != null, "Statement %s does not take argument.",
                currentStatement.getArgumentName());
    }

    private static String toPrefixedString(@Nullable final String prefix, final String localName) {
        if (prefix == null || prefix.isEmpty()) {
            return localName;
        }
        return prefix + ":" + localName;
    }

    private String toPrefixedString(final QName value) {
        final URI valueNs = value.getNamespace();
        final String valueLocal = value.getLocalName();
        if (currentModuleNs.equals(valueNs)) {
            return valueLocal;
        }
        final String prefix = ensureAndGetXmlNamespacePrefix(valueNs);
        return toPrefixedString(prefix, valueLocal);
    }

    private @Nullable String ensureAndGetXmlNamespacePrefix(final URI namespace) {
        if (YangConstants.RFC6020_YANG_NAMESPACE.equals(namespace)) {
            // YANG namespace does not have prefix if used in arguments.
            return null;

        }
        String prefix = writer.getNamespaceContext().getPrefix(namespace.toString());
        if (prefix == null) {
            // FIXME: declare prefix
            prefix = prefixToNamespace.inverse().get(namespace);
        }
        if (prefix == null) {
            throw new IllegalArgumentException("Namespace " + namespace + " is not bound to imported prefixes.");
        }
        return prefix;
    }

    private void writeXmlText(final String strRep) throws XMLStreamException {
        writer.writeCharacters(strRep);
    }

    private void declareXmlNamespaces(final Map<String, URI> prefixToNamespace) {
        try {
            writer.writeDefaultNamespace(YangConstants.RFC6020_YIN_NAMESPACE.toString());
            for (final Entry<String, URI> nsDeclaration : prefixToNamespace.entrySet()) {
                writer.writeNamespace(nsDeclaration.getKey(), nsDeclaration.getValue().toString());
            }
        } catch (final XMLStreamException e) {
            throw new IllegalStateException(e);
        }
    }

    private void writeXmlEndElement() throws XMLStreamException {
        writer.writeEndElement();
    }

    private void writeXmlArgument(final QName qName, final String value) throws XMLStreamException {
        writer.writeAttribute(qName.getNamespace().toString(), qName.getLocalName(), value);
    }

    private void writeStartXmlElement(final QName name) throws XMLStreamException {
        writer.writeStartElement(name.getNamespace().toString(), name.getLocalName());
    }
}