X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=yang%2Fyang-parser-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fyang%2Fparser%2Futil%2FModuleDependencySort.java;h=cf3045f9ceb6ebfcef282b37d8d5e8259dd4f1fe;hb=add54f1ae94f38ec842ab6810d5da2369d05422d;hp=f7e270ea1d5badf84ef605c51a93da8422739e9d;hpb=c9fde51a8e59bea47be9bc2055356d27db7498e0;p=yangtools.git diff --git a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ModuleDependencySort.java b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ModuleDependencySort.java index f7e270ea1d..cf3045f9ce 100644 --- a/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ModuleDependencySort.java +++ b/yang/yang-parser-impl/src/main/java/org/opendaylight/yangtools/yang/parser/util/ModuleDependencySort.java @@ -1,55 +1,41 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.yangtools.yang.parser.util; -import static java.util.Arrays.asList; - import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; -import com.google.common.base.Optional; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import java.net.URI; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; +import org.opendaylight.yangtools.yang.common.YangVersion; import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.ModuleImport; -import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder; -import org.opendaylight.yangtools.yang.parser.util.TopologicalSort.Node; import org.opendaylight.yangtools.yang.parser.util.TopologicalSort.NodeImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Creates a module dependency graph from provided {@link ModuleBuilder}s and - * provides a {@link #sort(ModuleBuilder...)} method. It is topological sort and + * Creates a module dependency graph from provided {@link Module}s and + * provides a {@link #sort(Module...)} method. It is topological sort and * returns modules in order in which they should be processed (e.g. if A imports * B, sort returns {B, A}). */ public final class ModuleDependencySort { - private static final Date DEFAULT_REVISION = new Date(0); - private static final Logger LOGGER = LoggerFactory.getLogger(ModuleDependencySort.class); - private static final Function TOPOLOGY_FUNCTION = new Function() { - @Override - public Module apply(final TopologicalSort.Node input) { - ModuleOrModuleBuilder moduleOrModuleBuilder = ((ModuleNodeImpl) input).getReference(); - return moduleOrModuleBuilder.getModule(); - } - }; + private static final Date DEFAULT_REVISION = SimpleDateFormatUtil.DEFAULT_DATE_REV; + private static final Logger LOG = LoggerFactory.getLogger(ModuleDependencySort.class); /** * It is not desirable to instance this class @@ -57,83 +43,44 @@ public final class ModuleDependencySort { private ModuleDependencySort() { } - - /** - * Extracts {@link ModuleBuilder} from a {@link ModuleNodeImpl}. - */ - private static final Function NODE_TO_MODULEBUILDER = new Function() { - @Override - public ModuleBuilder apply(final TopologicalSort.Node input) { - // Cast to ModuleBuilder from Node and return - ModuleOrModuleBuilder moduleOrModuleBuilder = ((ModuleNodeImpl) input).getReference(); - return moduleOrModuleBuilder.getModuleBuilder(); - } - }; - /** - * Topological sort of module builder dependency graph. + * Topological sort of module dependency graph. * - * @return Sorted list of Module builders. Modules can be further processed - * in returned order. + * @param modules YANG modules + * @return Sorted list of Modules. Modules can be further processed in + * returned order. */ - public static List sort(final ModuleBuilder... builders) { - return sort(asList(builders)); - } - - public static List sort(final Collection builders) { - List sorted = sortInternal(ModuleOrModuleBuilder.fromAll( - Collections.emptySet(),builders)); - return Lists.transform(sorted, NODE_TO_MODULEBUILDER); - } - - public static List sortWithContext(final SchemaContext context, final ModuleBuilder... builders) { - List all = ModuleOrModuleBuilder.fromAll(context.getModules(), asList(builders)); - - List sorted = sortInternal(all); - // Cast to ModuleBuilder from Node if possible and return - return Lists.transform(sorted, new Function() { - - @Override - public ModuleBuilder apply(final TopologicalSort.Node input) { - ModuleOrModuleBuilder moduleOrModuleBuilder = ((ModuleNodeImpl) input).getReference(); - if (moduleOrModuleBuilder.isModuleBuilder()) { - return moduleOrModuleBuilder.getModuleBuilder(); - } else { - return null; - } - } - }); + public static List sort(final Module... modules) { + return sort(Arrays.asList(modules)); } /** * Topological sort of module dependency graph. * + * @param modules YANG modules * @return Sorted list of Modules. Modules can be further processed in * returned order. */ - public static List sort(final Module... modules) { - List sorted = sortInternal(ModuleOrModuleBuilder.fromAll(asList(modules), - Collections.emptyList())); + public static List sort(final Iterable modules) { + final List sorted = sortInternal(modules); // Cast to Module from Node and return - return Lists.transform(sorted, TOPOLOGY_FUNCTION); + return Lists.transform(sorted, input -> input == null ? null : ((ModuleNodeImpl) input).getReference()); } - private static List sortInternal(final Iterable modules) { - Map> moduleGraph = createModuleGraph(modules); + private static List sortInternal(final Iterable modules) { + final Map> moduleGraph = createModuleGraph(modules); - Set nodes = Sets.newHashSet(); - for (Map map : moduleGraph.values()) { - for (ModuleNodeImpl node : map.values()) { - nodes.add(node); - } + final Set nodes = new HashSet<>(); + for (final Map map : moduleGraph.values()) { + nodes.addAll(map.values()); } return TopologicalSort.sort(nodes); } @VisibleForTesting - static Map> createModuleGraph(final Iterable builders) { - Map> moduleGraph = Maps.newHashMap(); + static Map> createModuleGraph(final Iterable builders) { + final Map> moduleGraph = new HashMap<>(); processModules(moduleGraph, builders); processDependencies(moduleGraph, builders); @@ -145,51 +92,24 @@ public final class ModuleDependencySort { * Extract module:revision from module builders */ private static void processDependencies(final Map> moduleGraph, - final Iterable mmbs) { - Map allNS = new HashMap<>(); + final Iterable mmbs) { + final Map allNS = new HashMap<>(); // Create edges in graph - for (ModuleOrModuleBuilder mmb : mmbs) { - Map imported = Maps.newHashMap(); - - String fromName; - Date fromRevision; - Collection imports; - URI ns; - - if (mmb.isModule()) { - Module module = mmb.getModule(); - fromName = module.getName(); - fromRevision = module.getRevision(); - imports = module.getImports(); - ns = module.getNamespace(); - } else { - ModuleBuilder moduleBuilder = mmb.getModuleBuilder(); - fromName = moduleBuilder.getName(); - fromRevision = moduleBuilder.getRevision(); - imports = moduleBuilder.getImports().values(); - ns = moduleBuilder.getNamespace(); - } + for (final Module module : mmbs) { + final Map imported = new HashMap<>(); + final String fromName = module.getName(); + final URI ns = module.getNamespace(); + Date fromRevision = module.getRevision(); // check for existence of module with same namespace - if (allNS.containsKey(ns)) { - ModuleOrModuleBuilder mod = allNS.get(ns); - String name = null; - Date revision = null; - if (mod.isModule()) { - name = mod.getModule().getName(); - revision = mod.getModule().getRevision(); - } else if (mod.isModuleBuilder()) { - name = mod.getModuleBuilder().getName(); - revision = mod.getModuleBuilder().getRevision(); + final Module prev = allNS.putIfAbsent(ns, module); + if (prev != null) { + final String name = prev.getName(); + if (!fromName.equals(name)) { + LOG.warn("Error while sorting module [{}, {}]: module with same namespace ({}) already loaded:" + + " [{}, {}]", fromName, fromRevision, ns, name, prev.getRevision()); } - if (!(fromName.equals(name))) { - LOGGER.warn( - "Error while sorting module [{}, {}]: module with same namespace ({}) already loaded: [{}, {}]", - fromName, fromRevision, ns, name, revision); - } - } else { - allNS.put(ns, mmb); } // no need to check if other Type of object, check is performed in @@ -199,22 +119,26 @@ public final class ModuleDependencySort { fromRevision = DEFAULT_REVISION; } - for (ModuleImport imprt : imports) { - String toName = imprt.getModuleName(); - Date toRevision = imprt.getRevision() == null ? DEFAULT_REVISION : imprt.getRevision(); + for (final ModuleImport imprt : module.getImports()) { + final String toName = imprt.getModuleName(); + final Date toRevision = imprt.getRevision() == null ? DEFAULT_REVISION : imprt.getRevision(); - ModuleNodeImpl from = moduleGraph.get(fromName).get(fromRevision); + final ModuleNodeImpl from = moduleGraph.get(fromName).get(fromRevision); - ModuleNodeImpl to = getModuleByNameAndRevision(moduleGraph, fromName, fromRevision, toName, toRevision); + final ModuleNodeImpl to = getModuleByNameAndRevision(moduleGraph, fromName, fromRevision, toName, toRevision); /* - * Check imports: If module is imported twice with different + * If it is an yang 1 module, check imports: If module is imported twice with different * revisions then throw exception */ - if (imported.get(toName) != null && !imported.get(toName).equals(toRevision) - && !imported.get(toName).equals(DEFAULT_REVISION) && !toRevision.equals(DEFAULT_REVISION)) { - ex(String.format("Module:%s imported twice with different revisions:%s, %s", toName, - formatRevDate(imported.get(toName)), formatRevDate(toRevision))); + if (YangVersion.VERSION_1.toString().equals(module.getYangVersion())) { + final Date impRevision = imported.get(toName); + if (impRevision != null && !impRevision.equals(toRevision) + && !DEFAULT_REVISION.equals(impRevision) && !DEFAULT_REVISION.equals(toRevision)) { + throw new YangValidationException(String.format( + "Module:%s imported twice with different revisions:%s, %s", toName, + formatRevDate(impRevision), formatRevDate(toRevision))); + } } imported.put(toName, toRevision); @@ -229,33 +153,31 @@ public final class ModuleDependencySort { */ private static ModuleNodeImpl getModuleByNameAndRevision(final Map> moduleGraph, final String fromName, final Date fromRevision, final String toName, final Date toRevision) { - ModuleNodeImpl to = null; - - if (moduleGraph.get(toName) == null || !moduleGraph.get(toName).containsKey(toRevision)) { - // If revision is not specified in import, but module exists - // with different revisions, take first - if (moduleGraph.get(toName) != null && !moduleGraph.get(toName).isEmpty() - && toRevision.equals(DEFAULT_REVISION)) { - to = moduleGraph.get(toName).values().iterator().next(); - LOGGER.trace(String - .format("Import:%s:%s by module:%s:%s does not specify revision, using:%s:%s for module dependency sort", - toName, formatRevDate(toRevision), fromName, formatRevDate(fromRevision), to.getName(), - formatRevDate(to.getRevision()))); - } else { - LOGGER.warn(String.format("Not existing module imported:%s:%s by:%s:%s", toName, - formatRevDate(toRevision), fromName, formatRevDate(fromRevision))); - LOGGER.warn("Available models: {}", moduleGraph); - ex(String.format("Not existing module imported:%s:%s by:%s:%s", toName, formatRevDate(toRevision), - fromName, formatRevDate(fromRevision))); + + final Map modulerevs = moduleGraph.get(toName); + if (modulerevs != null) { + final ModuleNodeImpl exact = modulerevs.get(toRevision); + if (exact != null) { + return exact; + } + + // If revision is not specified in import, but module exists with different revisions, take first one + if (DEFAULT_REVISION.equals(toRevision) && !modulerevs.isEmpty()) { + final ModuleNodeImpl first = modulerevs.values().iterator().next(); + if (LOG.isTraceEnabled()) { + LOG.trace("Import:{}:{} by module:{}:{} does not specify revision, using:{}:{}" + + " for module dependency sort", toName, formatRevDate(toRevision), fromName, + formatRevDate(fromRevision), first.getName(), formatRevDate(first.getRevision())); + } + return first; } - } else { - to = moduleGraph.get(toName).get(toRevision); } - return to; - } - private static void ex(final String message) { - throw new YangValidationException(message); + LOG.warn("Not existing module imported:{}:{} by:{}:{}", toName, formatRevDate(toRevision), fromName, + formatRevDate(fromRevision)); + LOG.warn("Available models: {}", moduleGraph); + throw new YangValidationException(String.format("Not existing module imported:%s:%s by:%s:%s", toName, + formatRevDate(toRevision), fromName, formatRevDate(fromRevision))); } /** @@ -263,35 +185,24 @@ public final class ModuleDependencySort { * graph */ private static void processModules(final Map> moduleGraph, - final Iterable builders) { + final Iterable modules) { // Process nodes - for (ModuleOrModuleBuilder momb : builders) { - - String name; - Date rev; - - if (momb.isModule()) { - name = momb.getModule().getName(); - rev = momb.getModule().getRevision(); - } else { - name = momb.getModuleBuilder().getName(); - rev = momb.getModuleBuilder().getRevision(); - } + for (final Module momb : modules) { + final String name = momb.getName(); + Date rev = momb.getRevision(); if (rev == null) { rev = DEFAULT_REVISION; } - if (moduleGraph.get(name) == null) { - moduleGraph.put(name, Maps. newHashMap()); + final Map revs = moduleGraph.computeIfAbsent(name, key -> new HashMap<>(2)); + if (revs.containsKey(rev)) { + throw new YangValidationException(String.format("Module:%s with revision:%s declared twice", name, + formatRevDate(rev))); } - if (moduleGraph.get(name).get(rev) != null) { - ex(String.format("Module:%s with revision:%s declared twice", name, formatRevDate(rev))); - } - - moduleGraph.get(name).put(rev, new ModuleNodeImpl(name, rev, momb)); + revs.put(rev, new ModuleNodeImpl(name, rev, momb)); } } @@ -303,12 +214,12 @@ public final class ModuleDependencySort { static class ModuleNodeImpl extends NodeImpl { private final String name; private final Date revision; - private final ModuleOrModuleBuilder originalObject; + private final Module originalObject; - public ModuleNodeImpl(final String name, final Date revision, final ModuleOrModuleBuilder builder) { + public ModuleNodeImpl(final String name, final Date revision, final Module module) { this.name = name; this.revision = revision; - this.originalObject = builder; + this.originalObject = module; } public String getName() { @@ -323,8 +234,8 @@ public final class ModuleDependencySort { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((revision == null) ? 0 : revision.hashCode()); + result = prime * result + Objects.hashCode(name); + result = prime * result + Objects.hashCode(revision); return result; } @@ -339,7 +250,7 @@ public final class ModuleDependencySort { if (getClass() != obj.getClass()) { return false; } - ModuleNodeImpl other = (ModuleNodeImpl) obj; + final ModuleNodeImpl other = (ModuleNodeImpl) obj; if (name == null) { if (other.name != null) { return false; @@ -362,47 +273,10 @@ public final class ModuleDependencySort { return "Module [name=" + name + ", revision=" + formatRevDate(revision) + "]"; } - public ModuleOrModuleBuilder getReference() { + public Module getReference() { return originalObject; } } } -class ModuleOrModuleBuilder { - private final Optional maybeModule; - private final Optional maybeModuleBuilder; - - ModuleOrModuleBuilder(final Module module) { - maybeModule = Optional.of(module); - maybeModuleBuilder = Optional.absent(); - } - - ModuleOrModuleBuilder(final ModuleBuilder moduleBuilder) { - maybeModule = Optional.absent(); - maybeModuleBuilder = Optional.of(moduleBuilder); - } - boolean isModule(){ - return maybeModule.isPresent(); - } - boolean isModuleBuilder(){ - return maybeModuleBuilder.isPresent(); - } - Module getModule(){ - return maybeModule.get(); - } - ModuleBuilder getModuleBuilder(){ - return maybeModuleBuilder.get(); - } - - static List fromAll(final Collection modules, final Collection moduleBuilders) { - List result = new ArrayList<>(modules.size() + moduleBuilders.size()); - for(Module m: modules){ - result.add(new ModuleOrModuleBuilder(m)); - } - for (ModuleBuilder mb : moduleBuilders) { - result.add(new ModuleOrModuleBuilder(mb)); - } - return result; - } -}