import javax.xml.transform.dom.DOMSource;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.rfc7952.model.api.AnnotationSchemaNode;
+import org.opendaylight.yangtools.yang.common.AnnotationName;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
@Override
String encodeAnnotationValue(final ValueWriter xmlWriter, final QName qname, final Object value)
throws XMLStreamException {
- final var optAnnotation = AnnotationSchemaNode.find(streamUtils.getEffectiveModelContext(), qname);
+ final var optAnnotation = AnnotationSchemaNode.find(streamUtils.getEffectiveModelContext(),
+ new AnnotationName(qname));
if (optAnnotation.isPresent()) {
return streamUtils.encodeValue(xmlWriter, resolveType(optAnnotation.orElseThrow().getType()), value,
qname.getModule());
import org.opendaylight.yangtools.rfc7952.model.api.AnnotationSchemaNode;
import org.opendaylight.yangtools.rfc8528.model.api.MountPointSchemaNode;
import org.opendaylight.yangtools.rfc8528.model.api.SchemaMountConstants;
+import org.opendaylight.yangtools.yang.common.AnnotationName;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.common.XMLNamespace;
final Optional<QNameModule> optModule = resolveXmlNamespace(attributeNS);
if (optModule.isPresent()) {
final QName qname = QName.create(optModule.orElseThrow(), localName);
- final var optAnnotation = AnnotationSchemaNode.find(codecs.getEffectiveModelContext(), qname);
+ final var optAnnotation = AnnotationSchemaNode.find(codecs.getEffectiveModelContext(),
+ new AnnotationName(qname));
if (optAnnotation.isPresent()) {
final AnnotationSchemaNode schema = optAnnotation.orElseThrow();
final Object value = codecs.codecFor(schema, stack)
--- /dev/null
+/*
+ * Copyright (c) 2019 PANTHEON.tech 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.common;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.Interner;
+import com.google.common.collect.Interners;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.yangtools.concepts.Identifier;
+import org.opendaylight.yangtools.concepts.WritableObject;
+
+/**
+ * Name of an individual YANG annotation, as defined in
+ * <a href="https://www.rfc-editor.org/rfc/rfc7952#section-5.2.1">RFC7952</a>.
+ */
+@NonNullByDefault
+public record AnnotationName(QName qname) implements Identifier, WritableObject {
+ @java.io.Serial
+ private static final long serialVersionUID = 1L;
+ private static final Interner<AnnotationName> INTERNER = Interners.newWeakInterner();
+
+ public AnnotationName {
+ requireNonNull(qname);
+ }
+
+ public AnnotationName intern() {
+ final var cacheQName = qname.intern();
+
+ // Identity comparison is here on purpose, as we are deciding whether to potentially store 'qname'. It is
+ // important that it does not hold user-supplied reference (such a String instance from parsing of an XML
+ // document).
+ final var template = cacheQName == qname ? this : new AnnotationName(cacheQName);
+
+ return INTERNER.intern(template);
+ }
+
+ public static AnnotationName readFrom(final DataInput in) throws IOException {
+ return new AnnotationName(QName.readFrom(in));
+ }
+
+ @Override
+ public void writeTo(final DataOutput out) throws IOException {
+ qname.writeTo(out);
+ }
+}
*
* @return The set of annotations attached to the corresponding data node.
*/
+ // FIXME: use AnnotationName instead of QName once we sort out the XML codec/NETCONF story
@NonNull Map<QName, Object> getAnnotations();
/**
package org.opendaylight.yangtools.rfc7952.model.api;
import com.google.common.annotations.Beta;
-import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.AnnotationName;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
import org.opendaylight.yangtools.yang.model.api.stmt.TypeDefinitionAware;
import org.opendaylight.yangtools.yang.model.api.stmt.UnknownEffectiveStatement;
* <a href="https://www.rfc-editor.org/rfc/rfc7952">RFC7952</a>.
*/
@Beta
-public interface AnnotationEffectiveStatement extends UnknownEffectiveStatement<QName, AnnotationStatement>,
+public interface AnnotationEffectiveStatement extends UnknownEffectiveStatement<AnnotationName, AnnotationStatement>,
TypeDefinitionAware {
@Override
default StatementDefinition statementDefinition() {
import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableMap.Builder;
import java.util.Map;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.common.AnnotationName;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.TypeAware;
import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
* Find specified annotation if it is supported by the specified SchemaContext.
*
* @param context SchemaContext to search
- * @param qname Annotation name
+ * @param name Annotation name
* @return {@link AnnotationSchemaNode} corresponding to specified name, or empty if it is not supported
* by the SchemaContext..
* @throws NullPointerException if any of the arguments is null
*/
- static @NonNull Optional<AnnotationSchemaNode> find(final SchemaContext context, final QName qname) {
- if (context instanceof AnnotationSchemaNodeAware) {
- return ((AnnotationSchemaNodeAware) context).findAnnotation(qname);
+ static @NonNull Optional<AnnotationSchemaNode> find(final SchemaContext context, final AnnotationName name) {
+ if (context instanceof AnnotationSchemaNodeAware aware) {
+ return aware.findAnnotation(name);
}
- return context.findModule(qname.getModule())
+ return context.findModule(name.qname().getModule())
.flatMap(module -> module.getUnknownSchemaNodes().stream()
.filter(AnnotationSchemaNode.class::isInstance)
.map(AnnotationSchemaNode.class::cast)
- .filter(annotation -> qname.equals(annotation.getQName()))
+ .filter(annotation -> name.equals(annotation.name()))
.findAny());
}
* @return {@link AnnotationSchemaNode}s supported by the SchemaContext..
* @throws NullPointerException if context is null
*/
- static @NonNull Map<QName, AnnotationSchemaNode> findAll(final SchemaContext context) {
- final Builder<QName, AnnotationSchemaNode> builder = ImmutableMap.builder();
- for (Module module : context.getModules()) {
- for (UnknownSchemaNode node : module.getUnknownSchemaNodes()) {
- if (node instanceof AnnotationSchemaNode) {
- builder.put(node.getQName(), (AnnotationSchemaNode) node);
+ static @NonNull Map<AnnotationName, AnnotationSchemaNode> findAll(final SchemaContext context) {
+ final var builder = ImmutableMap.<AnnotationName, AnnotationSchemaNode>builder();
+ for (var module : context.getModules()) {
+ for (var node : module.getUnknownSchemaNodes()) {
+ if (node instanceof AnnotationSchemaNode annotation) {
+ builder.put(annotation.name(), annotation);
}
}
}
-
return builder.build();
}
+ default @NonNull AnnotationName name() {
+ return asEffectiveStatement().argument();
+ }
+
+ @Override
+ default QName getQName() {
+ return name().qname();
+ }
+
@Override
AnnotationEffectiveStatement asEffectiveStatement();
}
import com.google.common.annotations.Beta;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.AnnotationName;
/**
* Interface for entities which can lookup {@link AnnotationSchemaNode}s based on their name.
- *
- * @author Robert Varga
*/
@Beta
public interface AnnotationSchemaNodeAware {
/**
* Find an annotation based on its QName.
*
- * @param qname Annotation name
+ * @param name Annotation name
* @return AnnotationSchemaNode if found
* @throws NullPointerException if {@code qname} is null
*/
- @NonNull Optional<AnnotationSchemaNode> findAnnotation(QName qname);
+ @NonNull Optional<AnnotationSchemaNode> findAnnotation(AnnotationName name);
}
package org.opendaylight.yangtools.rfc7952.model.api;
import com.google.common.annotations.Beta;
-import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.AnnotationName;
import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
import org.opendaylight.yangtools.yang.model.api.stmt.DocumentedDeclaredStatement.WithStatus;
import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureAwareDeclaredStatement;
* <a href="https://www.rfc-editor.org/rfc/rfc7952">RFC7952</a>.
*/
@Beta
-public interface AnnotationStatement extends UnknownStatement<QName>, WithStatus<QName>,
- IfFeatureAwareDeclaredStatement<QName>, TypeAwareDeclaredStatement {
+public interface AnnotationStatement extends UnknownStatement<AnnotationName>, WithStatus<AnnotationName>,
+ IfFeatureAwareDeclaredStatement<AnnotationName>, TypeAwareDeclaredStatement<AnnotationName> {
@Override
default StatementDefinition statementDefinition() {
return MetadataStatements.ANNOTATION;
}
+
+ @Override
+ default String rawArgument() {
+ return argument().qname().getLocalName();
+ }
}
/**
* Declared representation of a {@code leaf-list} statement.
*/
-public interface LeafListStatement extends MultipleElementsDeclaredStatement, TypeAwareDeclaredStatement,
+public interface LeafListStatement extends MultipleElementsDeclaredStatement, TypeAwareDeclaredStatement<QName>,
ConfigStatementAwareDeclaredStatement<QName>, MustStatementAwareDeclaredStatement<QName> {
@Override
default StatementDefinition statementDefinition() {
/**
* Declared representation of a {@code leaf} statement.
*/
-public interface LeafStatement extends DataDefinitionStatement, TypeAwareDeclaredStatement,
+public interface LeafStatement extends DataDefinitionStatement, TypeAwareDeclaredStatement<QName>,
ConfigStatementAwareDeclaredStatement<QName>, DefaultStatementAwareDeclaredStatement,
MandatoryStatementAwareDeclaredStatement<QName>, MustStatementAwareDeclaredStatement<QName> {
@Override
import com.google.common.annotations.Beta;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
@Beta
-public interface TypeAwareDeclaredStatement extends DeclaredStatement<QName> {
+public interface TypeAwareDeclaredStatement<A> extends DeclaredStatement<A> {
default @NonNull TypeStatement getType() {
return findFirstDeclaredSubstatement(TypeStatement.class).orElseThrow();
}
/**
* Declared representation of a {@code typedef} statement.
*/
-public interface TypedefStatement extends DocumentedDeclaredStatement.WithStatus<QName>, TypeAwareDeclaredStatement,
- DefaultStatementAwareDeclaredStatement {
+public interface TypedefStatement extends DocumentedDeclaredStatement.WithStatus<QName>,
+ TypeAwareDeclaredStatement<QName>, DefaultStatementAwareDeclaredStatement {
@Override
default StatementDefinition statementDefinition() {
return YangStmtMapping.TYPEDEF;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.rfc7952.model.api.AnnotationSchemaNode;
import org.opendaylight.yangtools.rfc7952.model.api.AnnotationSchemaNodeAwareSchemaContext;
-import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.AnnotationName;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.common.XMLNamespace;
import org.opendaylight.yangtools.yang.model.api.Module;
private final ImmutableSetMultimap<String, Module> nameToModules;
private final ImmutableMap<QNameModule, Module> moduleMap;
private final ImmutableSet<Module> modules;
- private final ImmutableMap<QName, AnnotationSchemaNode> annotations;
+ private final ImmutableMap<AnnotationName, AnnotationSchemaNode> annotations;
protected SimpleSchemaContext(final Collection<? extends @NonNull Module> modules) {
/*
}
@Override
- public final Optional<AnnotationSchemaNode> findAnnotation(final QName qname) {
+ public final Optional<AnnotationSchemaNode> findAnnotation(final AnnotationName qname) {
return Optional.ofNullable(annotations.get(requireNonNull(qname)));
}
import org.opendaylight.yangtools.rfc7952.model.api.AnnotationEffectiveStatement;
import org.opendaylight.yangtools.rfc7952.model.api.AnnotationSchemaNode;
import org.opendaylight.yangtools.rfc7952.model.api.AnnotationStatement;
+import org.opendaylight.yangtools.yang.common.AnnotationName;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
-final class AnnotationEffectiveStatementImpl extends AbstractEffectiveUnknownSchmemaNode<QName, AnnotationStatement>
+final class AnnotationEffectiveStatementImpl
+ extends AbstractEffectiveUnknownSchmemaNode<AnnotationName, AnnotationStatement>
implements AnnotationEffectiveStatement, AnnotationSchemaNode {
private final @NonNull TypeDefinition<?> type;
- AnnotationEffectiveStatementImpl(final Current<QName, AnnotationStatement> stmt,
+ AnnotationEffectiveStatementImpl(final Current<AnnotationName, AnnotationStatement> stmt,
final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
super(stmt.declared(), stmt.argument(), stmt.history(), substatements);
- final QName qname = stmt.getArgument();
+ final QName qname = stmt.getArgument().qname();
// FIXME: move this into onFullDefinitionDeclared()
final TypeEffectiveStatement<?> typeStmt = SourceException.throwIfNull(
type = builder.build();
}
- @Override
- public QName getQName() {
- return argument();
- }
-
@Override
public TypeDefinition<?> getType() {
return type;
*/
package org.opendaylight.yangtools.rfc7952.parser;
+import static java.util.Objects.requireNonNull;
+
import com.google.common.collect.ImmutableList;
+import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.rfc7952.model.api.AnnotationStatement;
-import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.AnnotationName;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
-import org.opendaylight.yangtools.yang.model.spi.meta.AbstractDeclaredStatement.WithQNameArgument.WithSubstatements;
+import org.opendaylight.yangtools.yang.model.spi.meta.AbstractDeclaredStatement;
+
+final class AnnotationStatementImpl extends AbstractDeclaredStatement<AnnotationName> implements AnnotationStatement {
+ private final @NonNull AnnotationName argument;
+ private final @NonNull Object substatements;
+
+ AnnotationStatementImpl(final AnnotationName argument,
+ final ImmutableList<? extends DeclaredStatement<?>> substatements) {
+ this.argument = requireNonNull(argument);
+ this.substatements = maskList(substatements);
+ }
+
+ @Override
+ public AnnotationName argument() {
+ return argument;
+ }
-final class AnnotationStatementImpl extends WithSubstatements implements AnnotationStatement {
- AnnotationStatementImpl(final QName argument, final ImmutableList<? extends DeclaredStatement<?>> substatements) {
- super(argument, substatements);
+ @Override
+ public ImmutableList<? extends DeclaredStatement<?>> declaredSubstatements() {
+ return unmaskList(substatements);
}
}
\ No newline at end of file
import org.opendaylight.yangtools.rfc7952.model.api.AnnotationEffectiveStatement;
import org.opendaylight.yangtools.rfc7952.model.api.AnnotationStatement;
import org.opendaylight.yangtools.rfc7952.model.api.MetadataStatements;
-import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.AnnotationName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
import org.opendaylight.yangtools.yang.parser.spi.meta.BoundStmtCtx;
import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport.StatementPolicy;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
public final class AnnotationStatementSupport
- extends AbstractStatementSupport<QName, AnnotationStatement, AnnotationEffectiveStatement> {
+ extends AbstractStatementSupport<AnnotationName, AnnotationStatement, AnnotationEffectiveStatement> {
private static final SubstatementValidator VALIDATOR = SubstatementValidator.builder(MetadataStatements.ANNOTATION)
.addMandatory(YangStmtMapping.TYPE)
.addOptional(YangStmtMapping.DESCRIPTION)
}
@Override
- public QName parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
- return StmtContextUtils.parseIdentifier(ctx, value);
+ public AnnotationName parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
+ return new AnnotationName(StmtContextUtils.parseIdentifier(ctx, value)).intern();
}
@Override
- public void onStatementAdded(final Mutable<QName, AnnotationStatement, AnnotationEffectiveStatement> stmt) {
+ public AnnotationName adaptArgumentValue(
+ final StmtContext<AnnotationName, AnnotationStatement, AnnotationEffectiveStatement> ctx,
+ final QNameModule targetModule) {
+ return new AnnotationName(ctx.getArgument().qname().bindTo(targetModule)).intern();
+ }
+
+ @Override
+ public void onStatementAdded(
+ final Mutable<AnnotationName, AnnotationStatement, AnnotationEffectiveStatement> stmt) {
final StatementDefinition parentDef = stmt.coerceParentContext().publicDefinition();
SourceException.throwIf(YangStmtMapping.MODULE != parentDef && YangStmtMapping.SUBMODULE != parentDef,
stmt, "Annotations may only be defined at root of either a module or a submodule");
}
@Override
- protected AnnotationStatement createDeclared(final BoundStmtCtx<QName> ctx,
+ protected AnnotationStatement createDeclared(final BoundStmtCtx<AnnotationName> ctx,
final ImmutableList<DeclaredStatement<?>> substatements) {
return new AnnotationStatementImpl(ctx.getArgument(), substatements);
}
}
@Override
- protected AnnotationEffectiveStatement createEffective(final Current<QName, AnnotationStatement> stmt,
+ protected AnnotationEffectiveStatement createEffective(final Current<AnnotationName, AnnotationStatement> stmt,
final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
return new AnnotationEffectiveStatementImpl(stmt, substatements);
}
package org.opendaylight.yangtools.rfc7952.parser;
import org.opendaylight.yangtools.rfc7952.model.api.AnnotationStatement;
-import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.AnnotationName;
import org.opendaylight.yangtools.yang.model.api.meta.DeclarationReference;
import org.opendaylight.yangtools.yang.model.spi.meta.AbstractRefStatement;
-final class RefAnnotationStatement extends AbstractRefStatement<QName, AnnotationStatement>
+final class RefAnnotationStatement extends AbstractRefStatement<AnnotationName, AnnotationStatement>
implements AnnotationStatement {
RefAnnotationStatement(final AnnotationStatement delegate, final DeclarationReference ref) {
super(delegate, ref);
*/
package org.opendaylight.yangtools.rfc7952.parser;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Optional;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.opendaylight.yangtools.rfc7952.model.api.AnnotationSchemaNode;
+import org.opendaylight.yangtools.yang.common.AnnotationName;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
import org.opendaylight.yangtools.yang.model.ri.type.BaseTypes;
import org.opendaylight.yangtools.yang.parser.stmt.reactor.CrossSourceStatementReactor;
public class AnnotationTest {
- private static final QName LAST_MODIFIED_QNAME = QName.create("http://example.org/example-last-modified",
- "last-modified");
+ private static final AnnotationName LAST_MODIFIED =
+ new AnnotationName(QName.create("http://example.org/example-last-modified", "last-modified"));
private static CrossSourceStatementReactor REACTOR;
@BeforeClass
final var annotations = AnnotationSchemaNode.findAll(context);
assertEquals(1, annotations.size());
- final var annotation = annotations.get(LAST_MODIFIED_QNAME);
+ final var annotation = annotations.get(LAST_MODIFIED);
assertNotNull(annotation);
- final var findAnnotation = AnnotationSchemaNode.find(context, LAST_MODIFIED_QNAME);
+ final var findAnnotation = AnnotationSchemaNode.find(context, LAST_MODIFIED);
assertTrue(findAnnotation.isPresent());
assertSame(annotation, findAnnotation.orElseThrow());