6fc637b59d024581f6f6ee80ca0f54a50988ce51
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / ImportStatementDefinition.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.ModelProcessingPhase.SOURCE_LINKAGE;
11 import static org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.SOURCE_PRE_LINKAGE;
12 import static org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils.firstAttributeOf;
13
14 import com.google.common.base.Optional;
15 import com.google.common.base.Verify;
16 import java.net.URI;
17 import java.util.Collection;
18 import java.util.Date;
19 import java.util.Map;
20 import java.util.Map.Entry;
21 import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil;
22 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
23 import org.opendaylight.yangtools.yang.model.api.Rfc6020Mapping;
24 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
25 import org.opendaylight.yangtools.yang.model.api.stmt.ImportStatement;
26 import org.opendaylight.yangtools.yang.model.api.stmt.ModuleStatement;
27 import org.opendaylight.yangtools.yang.model.api.stmt.NamespaceStatement;
28 import org.opendaylight.yangtools.yang.model.api.stmt.PrefixStatement;
29 import org.opendaylight.yangtools.yang.model.api.stmt.RevisionDateStatement;
30 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleIdentifierImpl;
31 import org.opendaylight.yangtools.yang.parser.spi.ModuleNamespace;
32 import org.opendaylight.yangtools.yang.parser.spi.PreLinkageModuleNamespace;
33 import org.opendaylight.yangtools.yang.parser.spi.SubstatementValidator;
34 import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
35 import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
36 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
37 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.InferenceAction;
38 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder.Prerequisite;
39 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
40 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
41 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToModuleIdentifier;
42 import org.opendaylight.yangtools.yang.parser.spi.source.ImpPrefixToNamespace;
43 import org.opendaylight.yangtools.yang.parser.spi.source.ModuleNameToNamespace;
44 import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.effective.ImportEffectiveStatementImpl;
45
46 public class ImportStatementDefinition
47         extends AbstractStatementSupport<String, ImportStatement, EffectiveStatement<String, ImportStatement>> {
48     private static final SubstatementValidator SUBSTATEMENT_VALIDATOR =
49             SubstatementValidator.builder(Rfc6020Mapping.IMPORT)
50             .add(Rfc6020Mapping.PREFIX, 1, 1).add(Rfc6020Mapping.REVISION_DATE, 0, 1).build();
51
52     public ImportStatementDefinition() {
53         super(Rfc6020Mapping.IMPORT);
54     }
55
56     @Override
57     public String parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
58         return value;
59     }
60
61     @Override
62     public ImportStatement createDeclared(final StmtContext<String, ImportStatement, ?> ctx) {
63         return new ImportStatementImpl(ctx);
64     }
65
66     @Override
67     public EffectiveStatement<String, ImportStatement> createEffective(
68             final StmtContext<String, ImportStatement, EffectiveStatement<String, ImportStatement>> ctx) {
69         return new ImportEffectiveStatementImpl(ctx);
70     }
71
72     @Override
73     public void onFullDefinitionDeclared(
74             final Mutable<String, ImportStatement, EffectiveStatement<String, ImportStatement>> stmt) {
75         super.onFullDefinitionDeclared(stmt);
76         SUBSTATEMENT_VALIDATOR.validate(stmt);
77     }
78
79     @Override
80     public void onPreLinkageDeclared(Mutable<String, ImportStatement, EffectiveStatement<String, ImportStatement>> stmt) {
81         final String moduleName = stmt.getStatementArgument();
82         final ModelActionBuilder importAction = stmt.newInferenceAction(SOURCE_PRE_LINKAGE);
83         final Prerequisite<StmtContext<?, ?, ?>> imported = importAction.requiresCtx(stmt,
84                 PreLinkageModuleNamespace.class, moduleName, SOURCE_PRE_LINKAGE);
85         final Prerequisite<Mutable<?, ?, ?>> linkageTarget = importAction
86                 .mutatesCtx(stmt.getRoot(), SOURCE_PRE_LINKAGE);
87
88         importAction.apply(new InferenceAction() {
89             @Override
90             public void apply() {
91                 StmtContext<?, ?, ?> importedModuleContext = imported.get();
92                 Verify.verify(moduleName.equals(importedModuleContext.getStatementArgument()));
93                 final URI importedModuleNamespace = importedModuleContext.getFromNamespace(ModuleNameToNamespace.class,
94                         moduleName);
95                 Verify.verifyNotNull(importedModuleNamespace);
96                 final String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class);
97                 Verify.verifyNotNull(impPrefix);
98                 stmt.addToNs(ImpPrefixToNamespace.class, impPrefix, importedModuleNamespace);
99             }
100
101             @Override
102             public void prerequisiteFailed(final Collection<? extends Prerequisite<?>> failed) {
103                 InferenceException.throwIf(failed.contains(imported), stmt.getStatementSourceReference(),
104                         "Imported module [%s] was not found.", moduleName);
105             }
106         });
107     }
108
109     @Override
110     public void onLinkageDeclared(
111             final Mutable<String, ImportStatement, EffectiveStatement<String, ImportStatement>> stmt) {
112         final ModuleIdentifier impIdentifier = getImportedModuleIdentifier(stmt);
113         final ModelActionBuilder importAction = stmt.newInferenceAction(SOURCE_LINKAGE);
114         final Prerequisite<StmtContext<?, ?, ?>> imported = importAction.requiresCtx(stmt, ModuleNamespace.class,
115             impIdentifier, SOURCE_LINKAGE);
116         final Prerequisite<Mutable<?, ?, ?>> linkageTarget = importAction.mutatesCtx(stmt.getRoot(), SOURCE_LINKAGE);
117
118         importAction.apply(new InferenceAction() {
119             @Override
120             public void apply() {
121                 StmtContext<?, ?, ?> importedModule = null;
122                 ModuleIdentifier importedModuleIdentifier = null;
123                 if (impIdentifier.getRevision() == SimpleDateFormatUtil.DEFAULT_DATE_IMP) {
124                     Entry<ModuleIdentifier, StmtContext<?, ModuleStatement, EffectiveStatement<String, ModuleStatement>>> recentModuleEntry =
125                             findRecentModule(impIdentifier, stmt.getAllFromNamespace(ModuleNamespace.class));
126                     if (recentModuleEntry != null) {
127                         importedModuleIdentifier = recentModuleEntry.getKey();
128                         importedModule = recentModuleEntry.getValue();
129                     }
130                 }
131
132                 if (importedModule == null || importedModuleIdentifier == null) {
133                     importedModule = imported.get();
134                     importedModuleIdentifier = impIdentifier;
135                 }
136
137                 linkageTarget.get().addToNs(ImportedModuleContext.class, importedModuleIdentifier, importedModule);
138                 String impPrefix = firstAttributeOf(stmt.declaredSubstatements(), PrefixStatement.class);
139                 stmt.addToNs(ImpPrefixToModuleIdentifier.class, impPrefix, importedModuleIdentifier);
140
141                 final URI modNs = firstAttributeOf(importedModule.declaredSubstatements(), NamespaceStatement.class);
142                 stmt.addToNs(URIStringToImpPrefix.class, modNs.toString(), impPrefix);
143             }
144
145             private Entry<ModuleIdentifier, StmtContext<?, ModuleStatement, EffectiveStatement<String, ModuleStatement>>> findRecentModule(
146                     final ModuleIdentifier impIdentifier,
147                     final Map<ModuleIdentifier, StmtContext<?, ModuleStatement, EffectiveStatement<String, ModuleStatement>>> allModules) {
148
149                 ModuleIdentifier recentModuleIdentifier = impIdentifier;
150                 Entry<ModuleIdentifier, StmtContext<?, ModuleStatement, EffectiveStatement<String, ModuleStatement>>> recentModuleEntry = null;
151
152                 for (Entry<ModuleIdentifier, StmtContext<?, ModuleStatement, EffectiveStatement<String, ModuleStatement>>> moduleEntry : allModules.entrySet()) {
153                     final ModuleIdentifier id = moduleEntry.getKey();
154
155                     if (id.getName().equals(impIdentifier.getName())
156                             && id.getRevision().compareTo(recentModuleIdentifier.getRevision()) > 0) {
157                         recentModuleIdentifier = id;
158                         recentModuleEntry = moduleEntry;
159                     }
160                 }
161
162                 return recentModuleEntry;
163             }
164
165             @Override
166             public void prerequisiteFailed(final Collection<? extends Prerequisite<?>> failed)  {
167                 if (failed.contains(imported)) {
168                     throw new InferenceException(stmt.getStatementSourceReference(),
169                         "Imported module [%s] was not found.", impIdentifier);
170                 }
171             }
172         });
173
174
175     }
176
177     private static ModuleIdentifier getImportedModuleIdentifier(final Mutable<String, ImportStatement, ?> stmt) {
178         Date revision = firstAttributeOf(stmt.declaredSubstatements(), RevisionDateStatement.class);
179         if (revision == null) {
180             revision = SimpleDateFormatUtil.DEFAULT_DATE_IMP;
181         }
182
183         return new ModuleIdentifierImpl(stmt.getStatementArgument(), Optional.absent(),
184                 Optional.of(revision));
185     }
186
187 }