Pick units from effective substatements
[yangtools.git] / yang / rfc7952-parser-support / src / main / java / org / opendaylight / yangtools / rfc7952 / parser / AnnotationStatementSupport.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies, s.r.o. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.rfc7952.parser;
9
10 import com.google.common.collect.ImmutableList;
11 import org.eclipse.jdt.annotation.NonNull;
12 import org.eclipse.jdt.annotation.Nullable;
13 import org.opendaylight.yangtools.rfc7952.model.api.AnnotationEffectiveStatement;
14 import org.opendaylight.yangtools.rfc7952.model.api.AnnotationSchemaNode;
15 import org.opendaylight.yangtools.rfc7952.model.api.AnnotationStatement;
16 import org.opendaylight.yangtools.rfc7952.model.api.MetadataStatements;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.model.api.SchemaNodeDefaults;
19 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
20 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
21 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
22 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
23 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
24 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
25 import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
26 import org.opendaylight.yangtools.yang.model.api.stmt.UnitsEffectiveStatement;
27 import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypeBuilder;
28 import org.opendaylight.yangtools.yang.model.util.type.ConcreteTypes;
29 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.AbstractDeclaredStatement.WithQNameArgument.WithSubstatements;
30 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.BaseStatementSupport;
31 import org.opendaylight.yangtools.yang.parser.rfc7950.stmt.UnknownEffectiveStatementBase;
32 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
33 import org.opendaylight.yangtools.yang.parser.spi.meta.SchemaPathSupport;
34 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
35 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
36 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
37 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
38 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
39
40 public final class AnnotationStatementSupport
41         extends BaseStatementSupport<QName, AnnotationStatement, AnnotationEffectiveStatement> {
42
43     private static final class Declared extends WithSubstatements implements AnnotationStatement {
44         Declared(final QName argument, final ImmutableList<? extends DeclaredStatement<?>> substatements) {
45             super(argument, substatements);
46         }
47     }
48
49     private static final class Effective extends UnknownEffectiveStatementBase<QName, AnnotationStatement>
50             implements AnnotationEffectiveStatement, AnnotationSchemaNode {
51
52         private final @NonNull TypeDefinition<?> type;
53         private final @Nullable SchemaPath path;
54
55         Effective(final Current<QName, AnnotationStatement> stmt,
56                   final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
57             super(stmt, substatements);
58             path = SchemaPathSupport.wrap(stmt.getEffectiveParent().getSchemaPath().createChild(argument()));
59
60             final TypeEffectiveStatement<?> typeStmt = SourceException.throwIfNull(
61                 firstSubstatementOfType(TypeEffectiveStatement.class), stmt,
62                 "AnnotationStatementSupport %s is missing a 'type' statement", argument());
63
64             final ConcreteTypeBuilder<?> builder = ConcreteTypes.concreteTypeBuilder(typeStmt.getTypeDefinition(),
65                 path);
66             final UnitsEffectiveStatement unitsStmt = firstSubstatementOfType(UnitsEffectiveStatement.class);
67             if (unitsStmt != null) {
68                 builder.setUnits(unitsStmt.argument());
69             }
70             type = builder.build();
71         }
72
73         @Override
74         public QName getQName() {
75             return path.getLastComponent();
76         }
77
78         @Override
79         @Deprecated
80         public SchemaPath getPath() {
81             return SchemaNodeDefaults.throwUnsupportedIfNull(this, path);
82         }
83
84         @Override
85         public TypeDefinition<?> getType() {
86             return type;
87         }
88
89         @Override
90         public TypeDefinition<?> getTypeDefinition() {
91             return type;
92         }
93
94         @Override
95         public AnnotationEffectiveStatement asEffectiveStatement() {
96             return this;
97         }
98     }
99
100     private static final AnnotationStatementSupport INSTANCE = new AnnotationStatementSupport(
101         MetadataStatements.ANNOTATION);
102
103     private final SubstatementValidator validator;
104
105     AnnotationStatementSupport(final StatementDefinition definition) {
106         super(definition, CopyPolicy.REJECT);
107         this.validator = SubstatementValidator.builder(definition)
108                 .addMandatory(YangStmtMapping.TYPE)
109                 .addOptional(YangStmtMapping.DESCRIPTION)
110                 .addAny(YangStmtMapping.IF_FEATURE)
111                 .addOptional(YangStmtMapping.REFERENCE)
112                 .addOptional(YangStmtMapping.STATUS)
113                 .addOptional(YangStmtMapping.UNITS)
114                 .build();
115     }
116
117     public static AnnotationStatementSupport getInstance() {
118         return INSTANCE;
119     }
120
121     @Override
122     public QName parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
123         return StmtContextUtils.parseIdentifier(ctx, value);
124     }
125
126     @Override
127     public void onStatementAdded(final Mutable<QName, AnnotationStatement, AnnotationEffectiveStatement> stmt) {
128         final StatementDefinition parentDef = stmt.coerceParentContext().publicDefinition();
129         SourceException.throwIf(YangStmtMapping.MODULE != parentDef && YangStmtMapping.SUBMODULE != parentDef,
130                 stmt, "Annotations may only be defined at root of either a module or a submodule");
131     }
132
133     @Override
134     protected SubstatementValidator getSubstatementValidator() {
135         return validator;
136     }
137
138     @Override
139     protected AnnotationStatement createDeclared(final StmtContext<QName, AnnotationStatement, ?> ctx,
140             final ImmutableList<? extends DeclaredStatement<?>> substatements) {
141         return new Declared(ctx.getArgument(), substatements);
142     }
143
144     @Override
145     protected AnnotationStatement createEmptyDeclared(final StmtContext<QName, AnnotationStatement, ?> ctx) {
146         return createDeclared(ctx, ImmutableList.of());
147     }
148
149     @Override
150     protected AnnotationEffectiveStatement createEffective(final Current<QName, AnnotationStatement> stmt,
151             final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
152         return new Effective(stmt, substatements);
153     }
154 }