/*
* Copyright (c) 2018 Pantheon Technologies, s.r.o. 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 static java.util.Objects.requireNonNull;
import static org.eclipse.jdt.annotation.DefaultLocation.PARAMETER;
import static org.eclipse.jdt.annotation.DefaultLocation.RETURN_TYPE;
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.annotation.concurrent.ThreadSafe;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement.QNameModuleToPrefixNamespace;
/**
* A YANG text snippet generated from a {@link DeclaredStatement}. Generated {@link #stream()} or {@link #iterator()}
* are guaranteed to not contain null nor empty strings. Furthermore, newlines are always emitted at the end
* on the generated string -- which can be checked with {@link #isEolString(String)} utility method.
*
*
* This allows individual strings to be escaped as needed and external indentation can be accounted for by inserting
* outer document indentation after the string which matched {@link #isEolString(String)} is emitted to the stream.
*
* @author Robert Varga
*/
@Beta
@ThreadSafe
@NonNullByDefault({ PARAMETER, RETURN_TYPE })
public final class YangTextSnippet implements Immutable, Iterable<@NonNull String> {
private final Set<@NonNull StatementDefinition> ignoredStatements;
private final Map mapper;
private final DeclaredStatement> statement;
private final boolean omitDefaultStatements;
private YangTextSnippet(final DeclaredStatement> statement,
final Map namespaces,
final Set<@NonNull StatementDefinition> ignoredStatements, final boolean omitDefaultStatements) {
this.statement = requireNonNull(statement);
this.mapper = requireNonNull(namespaces);
this.ignoredStatements = requireNonNull(ignoredStatements);
this.omitDefaultStatements = omitDefaultStatements;
}
public static Builder builder(final ModuleEffectiveStatement module, final DeclaredStatement> statement) {
return new Builder(module, statement);
}
@Override
public Iterator<@NonNull String> iterator() {
return new YangTextSnippetIterator(statement, mapper, ignoredStatements, omitDefaultStatements);
}
@Override
@SuppressWarnings("null")
public Spliterator<@NonNull String> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(),
Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL);
}
@SuppressWarnings("null")
public Stream<@NonNull String> stream() {
return StreamSupport.stream(spliterator(), false);
}
/**
* Check if an emitted string contains End-Of-Line character.
*
* @param str String to be checked
* @return True if the string contains end of line.
*/
public static boolean isEolString(final String str) {
return str.charAt(str.length() - 1) == '\n';
}
@Override
@SuppressWarnings("null")
public String toString() {
return stream().collect(Collectors.joining());
}
/**
* Builder class for instantiation of a customized {@link YangTextSnippet}.
*/
@Beta
public static final class Builder implements org.opendaylight.yangtools.concepts.Builder<@NonNull YangTextSnippet> {
private final List<@NonNull StatementDefinition> ignoredStatements = new ArrayList<>();
private final @NonNull DeclaredStatement> statement;
private final @NonNull ModuleEffectiveStatement module;
private boolean retainDefaultStatements;
Builder(final ModuleEffectiveStatement module, final DeclaredStatement> statement) {
this.module = requireNonNull(module);
this.statement = requireNonNull(statement);
}
/**
* Add a statement which should be skipped along with any of its children.
*
* @param statementDef Statement to be ignored
* @return This builder
*/
public Builder addIgnoredStatement(final StatementDefinition statementDef) {
ignoredStatements.add(requireNonNull(statementDef));
return this;
}
/**
* Retain common known statements whose argument matches semantics of not being present. By default these
* statements are omitted from output.
*
* @return This builder
*/
public Builder retainDefaultStatements() {
retainDefaultStatements = true;
return this;
}
@Override
public YangTextSnippet build() {
return new YangTextSnippet(statement, module.getAll(QNameModuleToPrefixNamespace.class),
ImmutableSet.copyOf(ignoredStatements), !retainDefaultStatements);
}
}
}