import org.opendaylight.yangtools.yang.model.api.UsesNode;
public abstract class AbstractSchemaContext implements SchemaContext {
+ /**
+ * A {@link Module} comparator based on {@link Module#getRevision()}, placing latest revision first. Note this
+ * comparator does not take into account module name and so two modules with different names but same revisions
+ * compare as equal.
+ */
protected static final Comparator<Module> REVISION_COMPARATOR =
- (first, second) -> Revision.compare(first.getRevision(), second.getRevision());
+ (first, second) -> Revision.compare(second.getRevision(), first.getRevision());
+
+ /**
+ * A {@link Module} comparator based on {@link Module#getName()} and {@link Module#getRevision()}, ordering modules
+ * lexicographically by their name and then in order of descending revision. This comparator assumes that
+ * the combination of these two attributes is sufficient to be consistent with hashCode/equals.
+ */
+ protected static final Comparator<Module> NAME_REVISION_COMPARATOR = (first, second) -> {
+ final int cmp = first.getName().compareTo(second.getName());
+ return cmp != 0 ? cmp : REVISION_COMPARATOR.compare(first, second);
+ };
+ /**
+ * Create a TreeSet for containing Modules with the same name, such that the set is ordered
+ * by {@link #REVISION_COMPARATOR}.
+ *
+ * @return A fresh TreeSet instance.
+ */
protected static final TreeSet<Module> createModuleSet() {
return new TreeSet<>(REVISION_COMPARATOR);
}
import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.TreeMultimap;
import java.net.URI;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
final Builder<Module> filteredModulesBuilder = new Builder<>();
// preparing map to get all modules with one name but difference in revision
- final TreeMultimap<String, Module> nameToModulesAll = getStringModuleTreeMultimap();
+ final TreeMultimap<String, Module> nameToModulesAll = TreeMultimap.create(String::compareTo,
+ REVISION_COMPARATOR);
nameToModulesAll.putAll(getStringModuleMap(delegate));
- // in case there is a particular dependancy to view filteredModules/yang models dependancy is checked
+ // in case there is a particular dependency to view filteredModules/YANG models dependency is checked
// for module name and imports
processForRootModules(delegate, rootModules, filteredModulesBuilder);
filteredModulesBuilder.build(), nameToModulesAll));
/**
- * Instead of doing this on each invocation of getModules(), pre-compute
- * it once and keep it around -- better than the set we got in.
+ * Instead of doing this on each invocation of getModules(), pre-compute it once and keep it around.
*/
- this.filteredModules = filteredModulesBuilder.build();
+ final List<Module> sortedModules = new ArrayList<>(filteredModulesBuilder.build());
+ sortedModules.sort(NAME_REVISION_COMPARATOR);
+ this.filteredModules = ImmutableSet.copyOf(sortedModules);
final SetMultimap<URI, Module> nsMap = Multimaps.newSetMultimap(new TreeMap<>(),
AbstractSchemaContext::createModuleSet);
moduleMap = moduleMapBuilder.build();
}
- private static TreeMultimap<String, Module> getStringModuleTreeMultimap() {
- return TreeMultimap.create(String::compareTo, REVISION_COMPARATOR);
- }
-
private static void processForAdditionalModules(final SchemaContext delegate,
final Set<ModuleId> additionalModuleIds, final Builder<Module> filteredModulesBuilder) {
filteredModulesBuilder.addAll(Collections2.filter(delegate.getModules(),
for (ModuleImport moduleImport : module.getImports()) {
Optional<Revision> revisionDate = moduleImport.getRevision();
if (!revisionDate.isPresent()) {
- revisionDate = nameToModulesAll.get(moduleImport.getModuleName()).last().getRevision();
+ revisionDate = nameToModulesAll.get(moduleImport.getModuleName()).first().getRevision();
}
ModuleId key = new ModuleId(moduleImport.getModuleName(), revisionDate);
--- /dev/null
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. 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.model.util;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.net.URI;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+public class SimpleSchemaContextTest {
+ @Test
+ public void testGetModulesOrdering() {
+ final Module foo0 = mockModule("foo", Optional.empty());
+ final Module foo1 = mockModule("foo", Revision.ofNullable("2018-01-01"));
+ final Module foo2 = mockModule("foo", Revision.ofNullable("2018-01-16"));
+
+ final List<Module> expected = ImmutableList.of(foo2, foo1, foo0);
+ assertGetModules(expected, foo0, foo1, foo2);
+ assertGetModules(expected, foo0, foo2, foo1);
+ assertGetModules(expected, foo1, foo0, foo2);
+ assertGetModules(expected, foo1, foo2, foo0);
+ assertGetModules(expected, foo2, foo0, foo1);
+ assertGetModules(expected, foo2, foo1, foo0);
+
+ assertFindModules(expected, "foo", foo0, foo1, foo2);
+ assertFindModules(expected, "foo", foo0, foo2, foo1);
+ assertFindModules(expected, "foo", foo1, foo0, foo2);
+ assertFindModules(expected, "foo", foo1, foo2, foo0);
+ assertFindModules(expected, "foo", foo2, foo0, foo1);
+ assertFindModules(expected, "foo", foo2, foo1, foo0);
+
+ final URI uri = URI.create("foo");
+ assertFindModules(expected, uri, foo0, foo1, foo2);
+ assertFindModules(expected, uri, foo0, foo2, foo1);
+ assertFindModules(expected, uri, foo1, foo0, foo2);
+ assertFindModules(expected, uri, foo1, foo2, foo0);
+ assertFindModules(expected, uri, foo2, foo0, foo1);
+ assertFindModules(expected, uri, foo2, foo1, foo0);
+ }
+
+ private static void assertGetModules(final List<Module> expected, final Module... modules) {
+ final Set<Module> actual = SimpleSchemaContext.forModules(ImmutableSet.copyOf(modules)).getModules();
+ assertArrayEquals(expected.toArray(), actual.toArray());
+ }
+
+ private static void assertFindModules(final List<Module> expected, final String name, final Module... modules) {
+ final Set<Module> actual = SimpleSchemaContext.forModules(ImmutableSet.copyOf(modules)).findModules(name);
+ assertArrayEquals(expected.toArray(), actual.toArray());
+ }
+
+ private static void assertFindModules(final List<Module> expected, final URI uri, final Module... modules) {
+ final Set<Module> actual = SimpleSchemaContext.forModules(ImmutableSet.copyOf(modules)).findModules(uri);
+ assertArrayEquals(expected.toArray(), actual.toArray());
+ }
+
+ private static Module mockModule(final String name, final Optional<Revision> revision) {
+ final QNameModule mod = QNameModule.create(URI.create(name), revision);
+ final Module ret = mock(Module.class);
+ doReturn(name).when(ret).getName();
+ doReturn(mod.getNamespace()).when(ret).getNamespace();
+ doReturn(mod.getRevision()).when(ret).getRevision();
+ doReturn(mod).when(ret).getQNameModule();
+ doReturn(mod.toString()).when(ret).toString();
+ return ret;
+ }
+}