import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import com.google.common.base.Splitter;
import com.google.common.collect.HashBiMap;
import com.google.common.io.ByteSource;
import java.io.File;
import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
import org.opendaylight.yangtools.yang.model.api.ModuleImport;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser;
import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
@Immutable
public final class YangParserImpl implements YangContextParser {
private static final Logger LOG = LoggerFactory.getLogger(YangParserImpl.class);
- private static final Splitter COLON_SPLITTER = Splitter.on(':');
private static final YangParserImpl INSTANCE = new YangParserImpl();
public static YangParserImpl getInstance() {
if (targetModule == null) {
Module result = findModuleFromContext(context, module, prefix, 0);
targetModule = new ModuleBuilder(result);
- TreeMap<Date, ModuleBuilder> map = modules.get(prefix);
+ TreeMap<Date, ModuleBuilder> map = modules.get(targetModule.getNamespace());
if (map == null) {
map = new TreeMap<>();
map.put(targetModule.getRevision(), targetModule);
}
public Collection<Module> buildModules(final Collection<ModuleBuilder> builders) {
- List<ModuleBuilder> sorted = ModuleDependencySort.sort(builders);
+ Collection<ModuleBuilder> unsorted = resolveSubmodules(builders);
+ List<ModuleBuilder> sorted = ModuleDependencySort.sort(unsorted);
Map<URI, TreeMap<Date, ModuleBuilder>> modules = resolveModulesWithImports(sorted, null);
Map<ModuleBuilder, Module> builderToModule = build(modules);
-
return builderToModule.values();
}
private Map<ByteSource, ModuleBuilder> resolveSubmodules(final Map<ByteSource, ModuleBuilder> builders) {
Map<ByteSource, ModuleBuilder> modules = new HashMap<>();
- Set<ModuleBuilder> submodules = new HashSet<>();
+ Map<String, TreeMap<Date, ModuleBuilder>> submodules = new HashMap<>();
for (Map.Entry<ByteSource, ModuleBuilder> entry : builders.entrySet()) {
- ModuleBuilder moduleBuilder = entry.getValue();
- if (moduleBuilder.isSubmodule()) {
- submodules.add(moduleBuilder);
+ ModuleBuilder builder = entry.getValue();
+ if (builder.isSubmodule()) {
+ String submoduleName = builder.getName();
+ TreeMap<Date, ModuleBuilder> map = submodules.get(submoduleName);
+ if (map == null) {
+ map = new TreeMap<>();
+ map.put(builder.getRevision(), builder);
+ submodules.put(submoduleName, map);
+ } else {
+ map.put(builder.getRevision(), builder);
+ }
} else {
- modules.put(entry.getKey(), moduleBuilder);
+ modules.put(entry.getKey(), builder);
}
}
- Collection<ModuleBuilder> values = modules.values();
- for (ModuleBuilder submodule : submodules) {
- for (ModuleBuilder module : values) {
- if (module.getName().equals(submodule.getBelongsTo())) {
- addSubmoduleToModule(submodule, module);
+ for (ModuleBuilder module : modules.values()) {
+ resolveSubmodules(module, submodules);
+ }
+
+ return modules;
+ }
+
+ private Collection<ModuleBuilder> resolveSubmodules(final Collection<ModuleBuilder> builders) {
+ Collection<ModuleBuilder> modules = new HashSet<>();
+ Map<String, TreeMap<Date, ModuleBuilder>> submodules = new HashMap<>();
+ for (ModuleBuilder builder : builders) {
+ if (builder.isSubmodule()) {
+ String submoduleName = builder.getName();
+ TreeMap<Date, ModuleBuilder> map = submodules.get(submoduleName);
+ if (map == null) {
+ map = new TreeMap<>();
+ map.put(builder.getRevision(), builder);
+ submodules.put(submoduleName, map);
+ } else {
+ map.put(builder.getRevision(), builder);
}
+ } else {
+ modules.add(builder);
}
}
+
+ for (ModuleBuilder module : modules) {
+ resolveSubmodules(module, submodules);
+ }
+
return modules;
}
* Traverse collection of builders, find builders representing submodule and
* add this submodule to its parent module.
*
- * @param builders
- * collection of builders containing modules and submodules
- * @return collection of module builders
+ * @param module
+ * current module
+ * @param submodules
+ * collection all loaded submodules
+ * @return collection of module builders with resolved submodules
*/
- private Collection<ModuleBuilder> resolveSubmodules(final Collection<ModuleBuilder> builders) {
- Collection<ModuleBuilder> modules = new HashSet<>();
- Set<ModuleBuilder> submodules = new HashSet<>();
- for (ModuleBuilder moduleBuilder : builders) {
- if (moduleBuilder.isSubmodule()) {
- submodules.add(moduleBuilder);
+ private void resolveSubmodules(final ModuleBuilder module,
+ final Map<String, TreeMap<Date, ModuleBuilder>> submodules) {
+ Map<String, Date> includes = module.getIncludedModules();
+ for (Map.Entry<String, Date> entry : includes.entrySet()) {
+ TreeMap<Date, ModuleBuilder> subs = submodules.get(entry.getKey());
+ if (subs == null) {
+ throw new YangParseException("Failed to find references submodule " + entry.getKey() + " in module "
+ + module.getName());
+ }
+ Date rev = entry.getValue();
+ ModuleBuilder submodule;
+ if (rev == null) {
+ submodule = subs.lastEntry().getValue();
} else {
- modules.add(moduleBuilder);
+ submodule = subs.get(rev);
+ // FIXME an exception should be thrown after issue with
+ // submodule's revisions and namespaces will be resolved
+ if (submodule == null) {
+ submodule = subs.lastEntry().getValue();
+ }
}
- }
- for (ModuleBuilder submodule : submodules) {
- for (ModuleBuilder module : modules) {
- if (module.getName().equals(submodule.getBelongsTo())) {
- addSubmoduleToModule(submodule, module);
- }
+ if (submodule.getIncludedModules().size() > 0) {
+ resolveSubmodules(submodule, submodules);
}
+ addSubmoduleToModule(submodule, module);
}
- return modules;
}
private void addSubmoduleToModule(final ModuleBuilder submodule, final ModuleBuilder module) {
+ module.addSubmodule(submodule);
submodule.setParent(module);
module.getDirtyNodes().addAll(submodule.getDirtyNodes());
module.getImports().putAll(submodule.getImports());
resolveUsesForNodes(modules);
resolveAugments(modules);
resolveIdentities(modules);
+ checkChoiceCasesForDuplicityQNames(modules);
// build
final Map<ModuleBuilder, Module> result = new LinkedHashMap<>();
augment.setResolved(true);
return true;
} else {
- throw new YangParseException(module.getName(), augment.getLine(), String.format(
- "Failed to resolve augment in uses. Invalid augment target: %s", potentialTargetNode));
+ LOG.warn(
+ "Error in module {} at line {}: Unsupported augment target: {}. Augmentation process skipped.",
+ module.getName(), augment.getLine(), potentialTargetNode);
+ augment.setResolved(true);
+ augment.setUnsupportedTarget(true);
+ return true;
}
} else {
throw new YangParseException(module.getName(), augment.getLine(), String.format(
}
}
- private void resolveIdentity(final ModuleBuilder module, final IdentitySchemaNodeBuilder identity) {
+ private void resolveIdentity(final ModuleBuilder module,
+ final IdentitySchemaNodeBuilder identity) {
final String baseIdentityName = identity.getBaseIdentityName();
if (baseIdentityName != null) {
IdentitySchemaNodeBuilder result = null;
final int line = identity.getLine();
String[] splittedBase = baseIdentityName.split(":");
if (splittedBase.length > 2) {
- throw new YangParseException(module.getName(), line, "Failed to parse identityref base: "
- + baseIdentityName);
+ throw new YangParseException(module.getName(), line,
+ "Failed to parse identityref base: "
+ + baseIdentityName);
}
String prefix = splittedBase[0];
String name = splittedBase[1];
- ModuleBuilder dependentModule = BuilderUtils.getModuleByPrefix(module, prefix);
- result = BuilderUtils.findIdentity(dependentModule.getAddedIdentities(), name);
+
+ if (prefix.equals(module.getPrefix())
+ && name.equals(identity.getQName().getLocalName())) {
+ throw new YangParseException(module.getName(),
+ identity.getLine(),
+ "Failed to parse base, identity name equals base identity name: "
+ + baseIdentityName);
+ }
+
+ ModuleBuilder dependentModule = BuilderUtils.getModuleByPrefix(
+ module, prefix);
+ result = BuilderUtils.findIdentity(
+ dependentModule.getAddedIdentities(), name);
} else {
- result = BuilderUtils.findIdentity(module.getAddedIdentities(), baseIdentityName);
+ if (baseIdentityName.equals(identity.getQName().getLocalName())) {
+ throw new YangParseException(module.getName(),
+ identity.getLine(),
+ "Failed to parse base, identity name equals base identity name: "
+ + baseIdentityName);
+ }
+ result = BuilderUtils.findIdentity(module.getAddedIdentities(),
+ baseIdentityName);
}
identity.setBaseIdentity(result);
}
ModuleBuilder module = BuilderUtils.getParentModule(usesNode);
final GroupingBuilder targetGroupingBuilder = GroupingUtils.getTargetGroupingFromModules(usesNode, modules,
module);
- if (targetGroupingBuilder == null) {
- throw new YangParseException(module.getName(), usesNode.getLine(), "Referenced grouping '"
- + usesNode.getGroupingPath() + "' not found.");
- }
usesNode.setGrouping(targetGroupingBuilder);
}
}
return null;
}
+
+ /**
+ * Traverse through modules and check if choice has choice cases with the
+ * same qname.
+ *
+ * @param modules
+ * all loaded modules
+ */
+ private void checkChoiceCasesForDuplicityQNames(final Map<URI, TreeMap<Date, ModuleBuilder>> modules) {
+ for (Map.Entry<URI, TreeMap<Date, ModuleBuilder>> entry : modules.entrySet()) {
+ for (Map.Entry<Date, ModuleBuilder> childEntry : entry.getValue().entrySet()) {
+ final ModuleBuilder moduleBuilder = childEntry.getValue();
+ final Module module = moduleBuilder.build();
+ final List<ChoiceNode> allChoicesFromModule = getChoicesFrom(module);
+
+ for (ChoiceNode choiceNode : allChoicesFromModule) {
+ findDuplicityNodesIn(choiceNode, module, moduleBuilder, modules);
+ }
+ }
+ }
+ }
+
+ private void findDuplicityNodesIn(final ChoiceNode choiceNode, final Module module, final ModuleBuilder moduleBuilder,
+ final Map<URI, TreeMap<Date, ModuleBuilder>> modules) {
+ final Set<QName> duplicityTestSet = new HashSet<QName>();
+
+ for (ChoiceCaseNode choiceCaseNode : choiceNode.getCases()) {
+
+ for (DataSchemaNode childSchemaNode : choiceCaseNode.getChildNodes()) {
+ if (!duplicityTestSet.add(childSchemaNode.getQName())) {
+ final Optional<SchemaNodeBuilder> schemaNodeBuilder = BuilderUtils.findSchemaNodeInModule(childSchemaNode.getPath(), moduleBuilder);
+ final String nameOfSchemaNode = childSchemaNode.getQName().getLocalName();
+ int lineOfSchemaNode = 0;
+
+ if (schemaNodeBuilder.isPresent()) {
+ lineOfSchemaNode = schemaNodeBuilder.get().getLine();
+ }
+ throw new YangParseException(module.getName(), lineOfSchemaNode,
+ String.format("Choice has two nodes case with same qnames - %s", nameOfSchemaNode));
+ }
+ }
+ }
+ }
+
+ private List<ChoiceNode> getChoicesFrom(final Module module) {
+ final List<ChoiceNode> allChoices = new ArrayList<ChoiceNode>();
+
+ for (DataSchemaNode dataSchemaNode : module.getChildNodes()) {
+ findChoicesIn(dataSchemaNode, allChoices);
+ }
+ return allChoices;
+ }
+
+ private void findChoicesIn(final SchemaNode schemaNode, final Collection<ChoiceNode> choiceNodes) {
+ if (schemaNode instanceof ContainerSchemaNode) {
+ final ContainerSchemaNode contSchemaNode = (ContainerSchemaNode) schemaNode;
+ for (DataSchemaNode dataSchemaNode : contSchemaNode.getChildNodes()) {
+ findChoicesIn(dataSchemaNode, choiceNodes);
+ }
+ } else if (schemaNode instanceof ListSchemaNode) {
+ final ListSchemaNode listSchemaNode = (ListSchemaNode) schemaNode;
+ for (DataSchemaNode dataSchemaNode : listSchemaNode.getChildNodes()) {
+ findChoicesIn(dataSchemaNode, choiceNodes);
+ }
+ } else if (schemaNode instanceof ChoiceNode) {
+ choiceNodes.add((ChoiceNode) schemaNode);
+ }
+ }
+
}