Migrate getDataChildByName() users
[yangtools.git] / yang / yang-model-util / src / main / java / org / opendaylight / yangtools / yang / model / util / AbstractSchemaContext.java
index e04d72a1b3d45c12d7f91186061bf7c1c0c2660f..913edc3b01d7d592148cc2b7a76f2c19911acc9b 100644 (file)
+/*
+ * Copyright (c) 2015 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.model.util;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Supplier;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimaps;
 import com.google.common.collect.SetMultimap;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.net.URI;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Date;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.TreeSet;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
-import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
-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(second.getRevision(), first.getRevision());
 
-    protected static final Supplier<TreeSet<Module>> MODULE_SET_SUPPLIER = new Supplier<TreeSet<Module>>() {
-        @Override
-        public TreeSet<Module> get() {
-            return new TreeSet<>(REVISION_COMPARATOR);
-        }
+    /**
+     * 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);
     };
 
-    protected static final Comparator<Module> REVISION_COMPARATOR = new Comparator<Module>() {
-        @Override
-        public int compare(final Module o1, final Module o2) {
-            if (o2.getRevision() == null) {
-                return -1;
-            }
+    /**
+     * 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);
+    }
 
-            return o2.getRevision().compareTo(o1.getRevision());
+    private static final VarHandle DERIVED_IDENTITIES;
+
+    static {
+        try {
+            DERIVED_IDENTITIES = MethodHandles.lookup().findVarHandle(AbstractSchemaContext.class, "derivedIdentities",
+                ImmutableMap.class);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new ExceptionInInitializerError(e);
         }
-    };
+    }
 
-    /**
-     * @return yang sources where key is ModuleIdentifier
-     */
-    protected abstract Map<ModuleIdentifier, String> getIdentifiersToSources();
+    // Accessed via DERIVED_IDENTITIES
+    @SuppressWarnings("unused")
+    private volatile ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> derivedIdentities = null;
 
     /**
+     * Returns the namespace-to-module mapping.
+     *
      * @return Map of modules where key is namespace
      */
     protected abstract SetMultimap<URI, Module> getNamespaceToModules();
 
     /**
+     * Returns the module name-to-module mapping.
+     *
      * @return Map of modules where key is name of module
      */
     protected abstract SetMultimap<String, Module> getNameToModules();
 
+    /**
+     * Returns the namespace+revision-to-module mapping.
+     *
+     * @return Map of modules where key is Module's QNameModule.
+     */
+    protected abstract Map<QNameModule, Module> getModuleMap();
+
     @Override
-    public Set<DataSchemaNode> getDataDefinitions() {
+    public Collection<? extends DataSchemaNode> getDataDefinitions() {
         final Set<DataSchemaNode> dataDefs = new HashSet<>();
         for (Module m : getModules()) {
             dataDefs.addAll(m.getChildNodes());
@@ -77,7 +118,7 @@ public abstract class AbstractSchemaContext implements SchemaContext {
     }
 
     @Override
-    public Set<NotificationDefinition> getNotifications() {
+    public Collection<? extends NotificationDefinition> getNotifications() {
         final Set<NotificationDefinition> notifications = new HashSet<>();
         for (Module m : getModules()) {
             notifications.addAll(m.getNotifications());
@@ -86,7 +127,7 @@ public abstract class AbstractSchemaContext implements SchemaContext {
     }
 
     @Override
-    public Set<RpcDefinition> getOperations() {
+    public Collection<? extends RpcDefinition> getOperations() {
         final Set<RpcDefinition> rpcs = new HashSet<>();
         for (Module m : getModules()) {
             rpcs.addAll(m.getRpcs());
@@ -95,7 +136,7 @@ public abstract class AbstractSchemaContext implements SchemaContext {
     }
 
     @Override
-    public Set<ExtensionDefinition> getExtensions() {
+    public Collection<? extends ExtensionDefinition> getExtensions() {
         final Set<ExtensionDefinition> extensions = new HashSet<>();
         for (Module m : getModules()) {
             extensions.addAll(m.getExtensionSchemaNodes());
@@ -104,82 +145,33 @@ public abstract class AbstractSchemaContext implements SchemaContext {
     }
 
     @Override
-    public Module findModuleByName(final String name, final Date revision) {
+    public Optional<? extends Module> findModule(final String name, final Optional<Revision> revision) {
         for (final Module module : getNameToModules().get(name)) {
-            if (revision == null || revision.equals(module.getRevision())) {
-                return module;
-            }
-        }
-
-        return null;
-    }
-
-    @Override
-    public Set<Module> findModuleByNamespace(final URI namespace) {
-        final Set<Module> ret = getNamespaceToModules().get(namespace);
-        return ret == null ? Collections.<Module>emptySet() : ret;
-    }
-
-    @Override
-    public Module findModuleByNamespaceAndRevision(final URI namespace, final Date revision) {
-        if (namespace == null) {
-            return null;
-        }
-        for (Module module : findModuleByNamespace(namespace)) {
-            if (revision == null || revision.equals(module.getRevision())) {
-                return module;
+            if (revision.equals(module.getRevision())) {
+                return Optional.of(module);
             }
         }
-        return null;
-    }
 
-    @Override
-    public boolean isAugmenting() {
-        return false;
+        return Optional.empty();
     }
 
     @Override
-    public boolean isAddedByUses() {
-        return false;
+    public Optional<Module> findModule(final QNameModule qnameModule) {
+        return Optional.ofNullable(getModuleMap().get(qnameModule));
     }
 
     @Override
-    public boolean isConfiguration() {
-        return false;
+    public Collection<? extends Module> findModules(final URI namespace) {
+        return getNamespaceToModules().get(namespace);
     }
 
     @Override
-    public ConstraintDefinition getConstraints() {
-        return null;
+    public Collection<? extends Module> findModules(final String name) {
+        return getNameToModules().get(name);
     }
 
     @Override
-    public QName getQName() {
-        return SchemaContext.NAME;
-    }
-
-    @Override
-    public SchemaPath getPath() {
-        return SchemaPath.ROOT;
-    }
-
-    @Override
-    public String getDescription() {
-        return null;
-    }
-
-    @Override
-    public String getReference() {
-        return null;
-    }
-
-    @Override
-    public Status getStatus() {
-        return Status.CURRENT;
-    }
-
-    @Override
-    public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+    public Collection<? extends UnknownSchemaNode> getUnknownSchemaNodes() {
         final List<UnknownSchemaNode> result = new ArrayList<>();
         for (Module module : getModules()) {
             result.addAll(module.getUnknownSchemaNodes());
@@ -188,7 +180,7 @@ public abstract class AbstractSchemaContext implements SchemaContext {
     }
 
     @Override
-    public Set<TypeDefinition<?>> getTypeDefinitions() {
+    public Collection<? extends TypeDefinition<?>> getTypeDefinitions() {
         final Set<TypeDefinition<?>> result = new LinkedHashSet<>();
         for (Module module : getModules()) {
             result.addAll(module.getTypeDefinitions());
@@ -197,7 +189,7 @@ public abstract class AbstractSchemaContext implements SchemaContext {
     }
 
     @Override
-    public Set<DataSchemaNode> getChildNodes() {
+    public Collection<? extends DataSchemaNode> getChildNodes() {
         final Set<DataSchemaNode> result = new LinkedHashSet<>();
         for (Module module : getModules()) {
             result.addAll(module.getChildNodes());
@@ -206,7 +198,7 @@ public abstract class AbstractSchemaContext implements SchemaContext {
     }
 
     @Override
-    public Set<GroupingDefinition> getGroupings() {
+    public Collection<? extends GroupingDefinition> getGroupings() {
         final Set<GroupingDefinition> result = new LinkedHashSet<>();
         for (Module module : getModules()) {
             result.addAll(module.getGroupings());
@@ -215,52 +207,52 @@ public abstract class AbstractSchemaContext implements SchemaContext {
     }
 
     @Override
-    public DataSchemaNode getDataChildByName(final QName name) {
+    public Optional<DataSchemaNode> findDataChildByName(final QName name) {
+        requireNonNull(name);
         for (Module module : getModules()) {
-            final DataSchemaNode result = module.getDataChildByName(name);
-            if (result != null) {
+            final Optional<DataSchemaNode> result = module.findDataChildByName(name);
+            if (result.isPresent()) {
                 return result;
             }
         }
-        return null;
+        return Optional.empty();
     }
 
     @Override
-    public DataSchemaNode getDataChildByName(final String name) {
-        for (Module module : getModules()) {
-            final DataSchemaNode result = module.getDataChildByName(name);
-            if (result != null) {
-                return result;
-            }
+    public Collection<? extends IdentitySchemaNode> getDerivedIdentities(final IdentitySchemaNode identity) {
+        ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> local =
+                (ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>>)
+                DERIVED_IDENTITIES.getAcquire(this);
+        if (local == null) {
+            local = loadDerivedIdentities();
         }
-        return null;
+        final ImmutableSet<IdentitySchemaNode> result = local.get(requireNonNull(identity));
+        checkArgument(result != null, "Identity %s not found", identity);
+        return result;
     }
 
-    @Override
-    public Set<UsesNode> getUses() {
-        return Collections.emptySet();
-    }
-
-    @Override
-    public boolean isPresenceContainer() {
-        return false;
-    }
-
-    @Override
-    public Set<AugmentationSchema> getAvailableAugmentations() {
-        return Collections.emptySet();
-    }
+    private ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> loadDerivedIdentities() {
+        final SetMultimap<IdentitySchemaNode, IdentitySchemaNode> tmp =
+                Multimaps.newSetMultimap(new HashMap<>(), HashSet::new);
+        final List<IdentitySchemaNode> identities = new ArrayList<>();
+        for (Module module : getModules()) {
+            final Collection<? extends IdentitySchemaNode> ids = module.getIdentities();
+            for (IdentitySchemaNode identity : ids) {
+                for (IdentitySchemaNode base : identity.getBaseIdentities()) {
+                    tmp.put(base, identity);
+                }
+            }
+            identities.addAll(ids);
+        }
 
-    //FIXME: should work for submodules too
-    @Override
-    public Set<ModuleIdentifier> getAllModuleIdentifiers() {
-        return getIdentifiersToSources().keySet();
-    }
+        final ImmutableMap.Builder<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> builder =
+                ImmutableMap.builderWithExpectedSize(identities.size());
+        for (IdentitySchemaNode identity : identities) {
+            builder.put(identity, ImmutableSet.copyOf(tmp.get(identity)));
+        }
 
-    @Override
-    public Optional<String> getModuleSource(final ModuleIdentifier moduleIdentifier) {
-        String maybeSource = getIdentifiersToSources().get(moduleIdentifier);
-        return Optional.fromNullable(maybeSource);
+        final ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>> result = builder.build();
+        final Object witness = DERIVED_IDENTITIES.compareAndExchangeRelease(this, null, result);
+        return witness == null ? result : (ImmutableMap<IdentitySchemaNode, ImmutableSet<IdentitySchemaNode>>) witness;
     }
-
 }