All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opendaylight.yangtools.yang.model.spi.AbstractSchemaContext Maven / Gradle / Ivy

/*
 * 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.spi;

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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
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.eclipse.jdt.annotation.NonNull;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.common.Revision;
import org.opendaylight.yangtools.yang.common.XMLNamespace;
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.NotificationDefinition;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;

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.
     */
    public static final Comparator REVISION_COMPARATOR =
        (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.
     */
    public static final Comparator 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 createModuleSet() {
        return new TreeSet<>(REVISION_COMPARATOR);
    }

    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);
        }
    }

    // Accessed via DERIVED_IDENTITIES
    @SuppressWarnings("unused")
    @SuppressFBWarnings(value = "URF_UNREAD_FIELD", justification = "https://github.com/spotbugs/spotbugs/issues/2749")
    private volatile ImmutableMap> derivedIdentities = null;

    /**
     * Returns the namespace-to-module mapping.
     *
     * @return Map of modules where key is namespace
     */
    protected abstract SetMultimap getNamespaceToModules();

    /**
     * Returns the module name-to-module mapping.
     *
     * @return Map of modules where key is name of module
     */
    protected abstract SetMultimap getNameToModules();

    /**
     * Returns the namespace+revision-to-module mapping.
     *
     * @return Map of modules where key is Module's QNameModule.
     */
    protected abstract Map getModuleMap();

    @Override
    public Collection getDataDefinitions() {
        final Set dataDefs = new HashSet<>();
        for (Module m : getModules()) {
            dataDefs.addAll(m.getChildNodes());
        }
        return dataDefs;
    }

    @Override
    public Collection getNotifications() {
        final Set notifications = new HashSet<>();
        for (Module m : getModules()) {
            notifications.addAll(m.getNotifications());
        }
        return notifications;
    }

    @Override
    public Collection getOperations() {
        final Set rpcs = new HashSet<>();
        for (Module m : getModules()) {
            rpcs.addAll(m.getRpcs());
        }
        return rpcs;
    }

    @Override
    public Collection getExtensions() {
        final Set extensions = new HashSet<>();
        for (Module m : getModules()) {
            extensions.addAll(m.getExtensionSchemaNodes());
        }
        return extensions;
    }

    @Override
    public Optional findModule(final String name, final Optional revision) {
        for (final Module module : getNameToModules().get(name)) {
            if (revision.equals(module.getRevision())) {
                return Optional.of(module);
            }
        }

        return Optional.empty();
    }

    @Override
    public Optional findModule(final QNameModule qnameModule) {
        return Optional.ofNullable(getModuleMap().get(qnameModule));
    }

    @Override
    public Collection findModules(final XMLNamespace namespace) {
        return getNamespaceToModules().get(namespace);
    }

    @Override
    public Collection findModules(final String name) {
        return getNameToModules().get(name);
    }

    @Override
    public Collection getUnknownSchemaNodes() {
        final List result = new ArrayList<>();
        for (Module module : getModules()) {
            result.addAll(module.getUnknownSchemaNodes());
        }
        return Collections.unmodifiableList(result);
    }

    @Override
    public Collection> getTypeDefinitions() {
        final Set> result = new LinkedHashSet<>();
        for (Module module : getModules()) {
            result.addAll(module.getTypeDefinitions());
        }
        return Collections.unmodifiableSet(result);
    }

    @Override
    public Collection getChildNodes() {
        final Set result = new LinkedHashSet<>();
        for (Module module : getModules()) {
            result.addAll(module.getChildNodes());
        }
        return Collections.unmodifiableSet(result);
    }

    @Override
    public Collection getGroupings() {
        final Set result = new LinkedHashSet<>();
        for (Module module : getModules()) {
            result.addAll(module.getGroupings());
        }
        return Collections.unmodifiableSet(result);
    }

    @Override
    public DataSchemaNode dataChildByName(final QName name) {
        requireNonNull(name);
        for (Module module : getModules()) {
            final DataSchemaNode result = module.dataChildByName(name);
            if (result != null) {
                return result;
            }
        }
        return null;
    }

    @Override
    public Collection getDerivedIdentities(final IdentitySchemaNode identity) {
        ImmutableMap> local =
                (ImmutableMap>)
                DERIVED_IDENTITIES.getAcquire(this);
        if (local == null) {
            local = loadDerivedIdentities();
        }
        final ImmutableSet result = local.get(requireNonNull(identity));
        if (result == null) {
            throw new IllegalArgumentException("Identity " + identity + " not found");
        }
        return result;
    }

    private ImmutableMap> loadDerivedIdentities() {
        final SetMultimap tmp =
                Multimaps.newSetMultimap(new HashMap<>(), HashSet::new);
        final List identities = new ArrayList<>();
        for (Module module : getModules()) {
            final Collection ids = module.getIdentities();
            for (IdentitySchemaNode identity : ids) {
                for (IdentitySchemaNode base : identity.getBaseIdentities()) {
                    tmp.put(base, identity);
                }
            }
            identities.addAll(ids);
        }

        final ImmutableMap.Builder> builder =
                ImmutableMap.builderWithExpectedSize(identities.size());
        for (IdentitySchemaNode identity : identities) {
            builder.put(identity, ImmutableSet.copyOf(tmp.get(identity)));
        }

        final ImmutableMap> result = builder.build();
        final Object witness = DERIVED_IDENTITIES.compareAndExchangeRelease(this, null, result);
        return witness == null ? result : (ImmutableMap>) witness;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy