Create all effective statements path Nullable
[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.UnitsStatement;
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 StmtContext<String, ?, ?> unitsStmt = StmtContextUtils.findFirstEffectiveSubstatement(
67                     stmt.caerbannog(), UnitsStatement.class);
68             if (unitsStmt != null) {
69                 builder.setUnits(unitsStmt.argument());
70             }
71             type = builder.build();
72         }
73
74         @Override
75         public QName getQName() {
76             return path.getLastComponent();
77         }
78
79         @Override
80         @Deprecated
81         public SchemaPath getPath() {
82             return SchemaNodeDefaults.throwUnsupportedIfNull(this, path);
83         }
84
85         @Override
86         public TypeDefinition<?> getType() {
87             return type;
88         }
89
90         @Override
91         public TypeDefinition<?> getTypeDefinition() {
92             return type;
93         }
94
95         @Override
96         public AnnotationEffectiveStatement asEffectiveStatement() {
97             return this;
98         }
99     }
100
101     private static final AnnotationStatementSupport INSTANCE = new AnnotationStatementSupport(
102         MetadataStatements.ANNOTATION);
103
104     private final SubstatementValidator validator;
105
106     AnnotationStatementSupport(final StatementDefinition definition) {
107         super(definition);
108         this.validator = SubstatementValidator.builder(definition)
109                 .addMandatory(YangStmtMapping.TYPE)
110                 .addOptional(YangStmtMapping.DESCRIPTION)
111                 .addAny(YangStmtMapping.IF_FEATURE)
112                 .addOptional(YangStmtMapping.REFERENCE)
113                 .addOptional(YangStmtMapping.STATUS)
114                 .addOptional(YangStmtMapping.UNITS)
115                 .build();
116     }
117
118     public static AnnotationStatementSupport getInstance() {
119         return INSTANCE;
120     }
121
122     @Override
123     public QName parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
124         return StmtContextUtils.parseIdentifier(ctx, value);
125     }
126
127     @Override
128     public void onStatementAdded(final Mutable<QName, AnnotationStatement, AnnotationEffectiveStatement> stmt) {
129         final StatementDefinition parentDef = stmt.coerceParentContext().publicDefinition();
130         SourceException.throwIf(YangStmtMapping.MODULE != parentDef && YangStmtMapping.SUBMODULE != parentDef,
131                 stmt, "Annotations may only be defined at root of either a module or a submodule");
132     }
133
134     @Override
135     protected SubstatementValidator getSubstatementValidator() {
136         return validator;
137     }
138
139     @Override
140     protected AnnotationStatement createDeclared(final StmtContext<QName, AnnotationStatement, ?> ctx,
141             final ImmutableList<? extends DeclaredStatement<?>> substatements) {
142         return new Declared(ctx.getArgument(), substatements);
143     }
144
145     @Override
146     protected AnnotationStatement createEmptyDeclared(final StmtContext<QName, AnnotationStatement, ?> ctx) {
147         return createDeclared(ctx, ImmutableList.of());
148     }
149
150     @Override
151     protected AnnotationEffectiveStatement createEffective(final Current<QName, AnnotationStatement> stmt,
152             final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
153         return new Effective(stmt, substatements);
154     }
155 }