Promote SchemaSourceRepresentation
[yangtools.git] / plugin / yang-maven-plugin / src / main / java / org / opendaylight / yangtools / yang2sources / plugin / ProcessorModuleReactor.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.yang2sources.plugin;
9
10 import static com.google.common.base.Preconditions.checkState;
11 import static com.google.common.base.Verify.verifyNotNull;
12 import static java.util.Objects.requireNonNull;
13
14 import com.google.common.base.MoreObjects;
15 import com.google.common.collect.ImmutableList;
16 import com.google.common.collect.Maps;
17 import com.google.common.io.CharStreams;
18 import java.io.IOException;
19 import java.io.Reader;
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.Map;
24 import java.util.Set;
25 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
26 import org.opendaylight.yangtools.yang.model.api.Module;
27 import org.opendaylight.yangtools.yang.model.api.Submodule;
28 import org.opendaylight.yangtools.yang.model.api.source.SourceIdentifier;
29 import org.opendaylight.yangtools.yang.model.spi.source.YangTextSource;
30 import org.opendaylight.yangtools.yang.parser.api.YangParser;
31 import org.opendaylight.yangtools.yang.parser.api.YangParserException;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * An incremental state reactor. Allows resolution of a SchemaContext based on a set of sources.
37  */
38 // FIXME: reneame to ExecutionModuleReactor or similar
39 final class ProcessorModuleReactor {
40     private static final Logger LOG = LoggerFactory.getLogger(ProcessorModuleReactor.class);
41
42     private final Map<SourceIdentifier, YangTextSource> modelsInProject;
43     private final Collection<ScannedDependency> dependencies;
44
45     private YangParser parser;
46
47     ProcessorModuleReactor(final YangParser parser, final Collection<YangTextSource> modelsInProject,
48             final Collection<ScannedDependency> dependencies) {
49         this.parser = requireNonNull(parser);
50         this.modelsInProject = Maps.uniqueIndex(modelsInProject, YangTextSource::sourceId);
51         this.dependencies = ImmutableList.copyOf(dependencies);
52     }
53
54     ContextHolder toContext() throws IOException, YangParserException {
55         checkState(parser != null, "Context has already been assembled");
56
57         for (var source : toUniqueSources(dependencies)) {
58             // This source is coming from a dependency:
59             // - its identifier should be accurate, as it should have been processed into a file with accurate name
60             // - it is not required to be parsed, hence we add it just as a library source
61             parser.addLibSource(source);
62         }
63
64         final EffectiveModelContext schemaContext = verifyNotNull(parser.buildEffectiveModel());
65         parser = null;
66
67         final Set<Module> modules = new HashSet<>();
68         for (Module module : schemaContext.getModules()) {
69             final SourceIdentifier modId = Util.moduleToIdentifier(module);
70             LOG.debug("Looking for source {}", modId);
71             if (modelsInProject.containsKey(modId)) {
72                 LOG.debug("Module {} belongs to current project", module);
73                 modules.add(module);
74
75                 for (Submodule sub : module.getSubmodules()) {
76                     final SourceIdentifier subId = Util.moduleToIdentifier(sub);
77                     if (!modelsInProject.containsKey(subId)) {
78                         LOG.warn("Submodule {} not found in input files", sub);
79                     }
80                 }
81             }
82         }
83
84         return new ContextHolder(schemaContext, modules, modelsInProject.keySet());
85     }
86
87     Collection<YangTextSource> getModelsInProject() {
88         return modelsInProject.values();
89     }
90
91     private static Collection<YangTextSource> toUniqueSources(final Collection<ScannedDependency> dependencies)
92             throws IOException {
93         final Map<String, YangTextSource> byContent = new HashMap<>();
94
95         for (ScannedDependency dependency : dependencies) {
96             for (YangTextSource s : dependency.sources()) {
97                 try (Reader reader = s.openStream()) {
98                     final String contents = CharStreams.toString(reader);
99                     byContent.putIfAbsent(contents, s);
100                 }
101             }
102         }
103         return byContent.values();
104     }
105
106     @Override
107     public String toString() {
108         return MoreObjects.toStringHelper(this).add("sources", modelsInProject.keySet()).toString();
109     }
110 }