BUG-4688: Switch BelongsToModuleContext to SourceIdentifier
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / ModuleStatementSupport.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. 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.yang.parser.stmt.rfc6020;
9
10 import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
11
12 import java.net.URI;
13 import java.util.Date;
14 import java.util.NavigableMap;
15 import java.util.Optional;
16 import java.util.TreeMap;
17 import org.opendaylight.yangtools.concepts.SemVer;
18 import org.opendaylight.yangtools.yang.common.QNameModule;
19 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
20 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
21 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
22 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
23 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
24 import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement;
25 import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
26 import org.opendaylight.yangtools.yang.model.util.ModuleIdentifierImpl;
27 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
28 import org.opendaylight.yangtools.yang.parser.spi.NamespaceToModule;
29 import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace;
30 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
31 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionModuleNamespace;
32 import org.opendaylight.yangtools.yang.parser.spi.meta.SemanticVersionNamespace;
33 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
34 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
35 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
36 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
37 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToModuleIdentifier;
38 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
39 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleIdentifier;
40 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleCtxToModuleQName;
41 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleIdentifierToModuleQName;
42 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToModuleQName;
43 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
44 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNamespaceForBelongsTo;
45 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleQNameToModuleName;
46 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
47 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
48 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ModuleEffectiveStatementImpl;
49
50 public class ModuleStatementSupport extends
51         AbstractStatementSupport<String, ModuleStatement, EffectiveStatement<String, ModuleStatement>> {
52     private static final SubstatementValidator SUBSTATEMENT_VALIDATOR = SubstatementValidator.builder(YangStmtMapping
53             .MODULE)
54             .addAny(YangStmtMapping.ANYXML)
55             .addAny(YangStmtMapping.AUGMENT)
56             .addAny(YangStmtMapping.CHOICE)
57             .addOptional(YangStmtMapping.CONTACT)
58             .addAny(YangStmtMapping.CONTAINER)
59             .addOptional(YangStmtMapping.DESCRIPTION)
60             .addAny(YangStmtMapping.DEVIATION)
61             .addAny(YangStmtMapping.EXTENSION)
62             .addAny(YangStmtMapping.FEATURE)
63             .addAny(YangStmtMapping.GROUPING)
64             .addAny(YangStmtMapping.IDENTITY)
65             .addAny(YangStmtMapping.IMPORT)
66             .addAny(YangStmtMapping.INCLUDE)
67             .addAny(YangStmtMapping.LEAF)
68             .addAny(YangStmtMapping.LEAF_LIST)
69             .addAny(YangStmtMapping.LIST)
70             .addMandatory(YangStmtMapping.NAMESPACE)
71             .addAny(YangStmtMapping.NOTIFICATION)
72             .addOptional(YangStmtMapping.ORGANIZATION)
73             .addMandatory(YangStmtMapping.PREFIX)
74             .addOptional(YangStmtMapping.REFERENCE)
75             .addAny(YangStmtMapping.REVISION)
76             .addAny(YangStmtMapping.RPC)
77             .addAny(YangStmtMapping.TYPEDEF)
78             .addAny(YangStmtMapping.USES)
79             .addOptional(YangStmtMapping.YANG_VERSION)
80             .addOptional(SupportedExtensionsMapping.OPENCONFIG_VERSION)
81             .build();
82
83     public ModuleStatementSupport() {
84         super(YangStmtMapping.MODULE);
85     }
86
87     @Override
88     public String parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
89         return value;
90     }
91
92     @Override
93     public ModuleStatement createDeclared(final StmtContext<String, ModuleStatement, ?> ctx) {
94         return new ModuleStatementImpl(ctx);
95     }
96
97     @Override
98     public EffectiveStatement<String, ModuleStatement> createEffective(
99             final StmtContext<String, ModuleStatement, EffectiveStatement<String, ModuleStatement>> ctx) {
100         return new ModuleEffectiveStatementImpl(ctx);
101     }
102
103     @Override
104     public void onPreLinkageDeclared(final Mutable<String, ModuleStatement,
105             EffectiveStatement<String, ModuleStatement>> stmt) {
106         final String moduleName = stmt.getStatementArgument();
107
108         final URI moduleNs = firstAttributeOf(stmt.declaredSubstatements(), NamespaceStatement.class);
109         SourceException.throwIfNull(moduleNs, stmt.getStatementSourceReference(),
110             "Namespace of the module [%s] is missing", stmt.getStatementArgument());
111         stmt.addToNs(ModuleNameToNamespace.class, moduleName, moduleNs);
112
113         final String modulePrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class);
114         SourceException.throwIfNull(modulePrefix, stmt.getStatementSourceReference(),
115             "Prefix of the module [%s] is missing", stmt.getStatementArgument());
116         stmt.addToNs(ImpPrefixToNamespace.class, modulePrefix, moduleNs);
117
118         stmt.addContext(PreLinkageModuleNamespace.class, moduleName, stmt);
119
120         Optional<Date> revisionDate = Optional.ofNullable(StmtContextUtils.getLatestRevision(
121             stmt.declaredSubstatements()));
122         if (!revisionDate.isPresent()) {
123             revisionDate = Optional.of(SimpleDateFormatUtil.DEFAULT_DATE_REV);
124         }
125
126         final QNameModule qNameModule = QNameModule.create(moduleNs, revisionDate.orElse(null)).intern();
127
128         stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule);
129         stmt.setRootIdentifier(ModuleIdentifierImpl.create(stmt.getStatementArgument(),
130                 Optional.empty(), revisionDate));
131     }
132
133     @Override
134     public void onLinkageDeclared(final Mutable<String, ModuleStatement,
135             EffectiveStatement<String, ModuleStatement>> stmt) {
136
137         final Optional<URI> moduleNs = Optional.ofNullable(firstAttributeOf(stmt.declaredSubstatements(),
138                 NamespaceStatement.class));
139         SourceException.throwIf(!moduleNs.isPresent(), stmt.getStatementSourceReference(),
140             "Namespace of the module [%s] is missing", stmt.getStatementArgument());
141
142         Optional<Date> revisionDate = Optional.ofNullable(StmtContextUtils.getLatestRevision(
143             stmt.declaredSubstatements()));
144         if (!revisionDate.isPresent()) {
145             revisionDate = Optional.of(SimpleDateFormatUtil.DEFAULT_DATE_REV);
146         }
147
148         final QNameModule qNameModule = QNameModule.create(moduleNs.get(), revisionDate.orElse(null)).intern();
149         final StmtContext<?, ModuleStatement, EffectiveStatement<String, ModuleStatement>> possibleDuplicateModule =
150                 stmt.getFromNamespace(NamespaceToModule.class, qNameModule);
151         if (possibleDuplicateModule != null && possibleDuplicateModule != stmt) {
152             throw new SourceException(stmt.getStatementSourceReference(), "Module namespace collision: %s. At %s",
153                     qNameModule.getNamespace(), possibleDuplicateModule.getStatementSourceReference());
154         }
155
156         final ModuleIdentifier moduleIdentifier = ModuleIdentifierImpl.create(stmt.getStatementArgument(),
157                 Optional.empty(), revisionDate);
158
159         stmt.addContext(ModuleNamespace.class, moduleIdentifier, stmt);
160         stmt.addContext(ModuleNamespaceForBelongsTo.class, moduleIdentifier.getName(), stmt);
161         stmt.addContext(NamespaceToModule.class, qNameModule, stmt);
162
163         final String modulePrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class);
164         SourceException.throwIfNull(modulePrefix, stmt.getStatementSourceReference(),
165             "Prefix of the module [%s] is missing", stmt.getStatementArgument());
166
167         stmt.addToNs(PrefixToModule.class, modulePrefix, qNameModule);
168         stmt.addToNs(ModuleNameToModuleQName.class, stmt.getStatementArgument(), qNameModule);
169         stmt.addToNs(ModuleCtxToModuleQName.class, stmt, qNameModule); // tu
170         stmt.addToNs(ModuleCtxToModuleIdentifier.class, stmt, moduleIdentifier);
171         stmt.addToNs(ModuleQNameToModuleName.class, qNameModule, stmt.getStatementArgument());
172         stmt.addToNs(ModuleIdentifierToModuleQName.class, moduleIdentifier, qNameModule);
173         stmt.addToNs(ImpPrefixToModuleIdentifier.class, modulePrefix, moduleIdentifier);
174
175         if (stmt.isEnabledSemanticVersioning()) {
176             addToSemVerModuleNamespace(stmt);
177         }
178     }
179
180     private static int compareNullableSemVer(final SemVer ver1, final SemVer ver2) {
181         if (ver1 == null) {
182             return ver2 == null ? 0 : -1;
183         }
184
185         return ver2 == null ? 1 : ver1.compareTo(ver2);
186     }
187
188     private static void addToSemVerModuleNamespace(
189             final Mutable<String, ModuleStatement, EffectiveStatement<String, ModuleStatement>> stmt) {
190         final String moduleName = stmt.getStatementArgument();
191         NavigableMap<SemVer, StmtContext<?, ?, ?>> modulesMap = stmt.getFromNamespace(
192                 SemanticVersionModuleNamespace.class, moduleName);
193         if (modulesMap == null) {
194             modulesMap = new TreeMap<>(ModuleStatementSupport::compareNullableSemVer);
195         }
196         final SemVer moduleSemVer = stmt.getFromNamespace(SemanticVersionNamespace.class, stmt);
197         modulesMap.put(moduleSemVer, stmt);
198         stmt.addToNs(SemanticVersionModuleNamespace.class, moduleName, modulesMap);
199     }
200
201     @Override
202     protected SubstatementValidator getSubstatementValidator() {
203         return SUBSTATEMENT_VALIDATOR;
204     }
205 }