/* * 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.parser.spi.meta; import com.google.common.base.Preconditions; import com.google.common.collect.HashBasedTable; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableTable; import com.google.common.collect.Table; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.YangVersion; import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; public final class StatementSupportBundle implements Immutable, NamespaceBehaviour.Registry { private static final StatementSupportBundle EMPTY = new StatementSupportBundle(null, null, ImmutableMap.of(), ImmutableMap.of(), ImmutableTable.of()); private final StatementSupportBundle parent; private final ImmutableMap<QName, StatementSupport<?, ?, ?>> commonDefinitions; private final ImmutableTable<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificDefinitions; private final ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaceDefinitions; private final Set<YangVersion> supportedVersions; private StatementSupportBundle(final StatementSupportBundle parent, final Set<YangVersion> supportedVersions, final ImmutableMap<QName, StatementSupport<?, ?, ?>> commonStatements, final ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces, final ImmutableTable<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificStatements) { this.parent = parent; this.supportedVersions = supportedVersions; this.commonDefinitions = commonStatements; this.namespaceDefinitions = namespaces; this.versionSpecificDefinitions = versionSpecificStatements; } /** * Returns statement definitions common for all versions * * @return map of common statement definitions */ public ImmutableMap<QName, StatementSupport<?, ?, ?>> getCommonDefinitions() { return commonDefinitions; } /** * Returns statement definitions specific for requested version. Result of * this method doesn't include common statement definitions. * * @param version * requested version * @return map of statement definitions specific for requested version, it * doesn't include common statement definitions. */ public ImmutableMap<QName, StatementSupport<?, ?, ?>> getDefinitionsSpecificForVersion(final YangVersion version) { return versionSpecificDefinitions.row(version); } /** * Returns all version specific statement definitions. Result of this method * doesn't include common statement definitions. * * @return table of all version specific statement definitions, it doesn't * include common statement definitions. */ public ImmutableTable<YangVersion, QName, StatementSupport<?, ?, ?>> getAllVersionSpecificDefinitions() { return versionSpecificDefinitions; } public ImmutableMap<Class<?>, NamespaceBehaviour<?, ?, ?>> getNamespaceDefinitions() { return namespaceDefinitions; } public static Builder builder(final Set<YangVersion> supportedVersions) { return new Builder(supportedVersions, EMPTY); } public static Builder derivedFrom(final StatementSupportBundle parent) { Preconditions.checkNotNull(parent); return new Builder(parent.getSupportedVersions(), parent); } public Set<YangVersion> getSupportedVersions() { return supportedVersions; } @Override public <K, V, N extends IdentifierNamespace<K, V>> NamespaceBehaviour<K, V, N> getNamespaceBehaviour( final Class<N> namespace) throws NamespaceNotAvailableException { final NamespaceBehaviour<?, ?, ?> potential = namespaceDefinitions.get(namespace); if (potential != null) { Preconditions.checkState(namespace.equals(potential.getIdentifier())); /* * Safe cast, previous checkState checks equivalence of key from * which type argument are derived */ return (NamespaceBehaviour<K, V, N>) potential; } if (parent != null) { return parent.getNamespaceBehaviour(namespace); } return null; } public <K, V, N extends IdentifierNamespace<K, V>> boolean hasNamespaceBehaviour(final Class<N> namespace) { if (namespaceDefinitions.containsKey(namespace)) { return true; } if (parent != null) { return parent.hasNamespaceBehaviour(namespace); } return false; } public StatementSupport<?, ?, ?> getStatementDefinition(final YangVersion version, final QName stmtName) { StatementSupport<?, ?, ?> result = getVersionSpecificStatementDefinition(version, stmtName); if (result == null) { result = getCommonStatementDefinition(stmtName); } return result; } private StatementSupport<?, ?, ?> getCommonStatementDefinition(final QName stmtName) { final StatementSupport<?, ?, ?> potential = commonDefinitions.get(stmtName); if (potential != null) { return potential; } if (parent != null) { return parent.getCommonStatementDefinition(stmtName); } return null; } private StatementSupport<?, ?, ?> getVersionSpecificStatementDefinition(final YangVersion version, final QName stmtName) { final StatementSupport<?, ?, ?> potential = versionSpecificDefinitions.get(version, stmtName); if (potential != null) { return potential; } if (parent != null) { return parent.getVersionSpecificStatementDefinition(version, stmtName); } return null; } public static class Builder implements org.opendaylight.yangtools.concepts.Builder<StatementSupportBundle> { private final Map<QName, StatementSupport<?, ?, ?>> commonStatements = new HashMap<>(); private final Table<YangVersion, QName, StatementSupport<?, ?, ?>> versionSpecificStatements = HashBasedTable .create(); private final Map<Class<?>, NamespaceBehaviour<?, ?, ?>> namespaces = new HashMap<>(); private final Set<YangVersion> supportedVersions; private StatementSupportBundle parent; Builder(final Set<YangVersion> supportedVersions, final StatementSupportBundle parent) { this.parent = Preconditions.checkNotNull(parent); this.supportedVersions = ImmutableSet.copyOf(supportedVersions); } public Builder addSupport(final StatementSupport<?, ?, ?> definition) { final QName identifier = definition.getStatementName(); Preconditions.checkState(!commonStatements.containsKey(identifier), "Statement %s already defined in common statement bundle.", identifier); Preconditions.checkState(parent.getCommonStatementDefinition(identifier) == null, "Statement %s already defined.", identifier); commonStatements.put(identifier, definition); return this; } public Builder addVersionSpecificSupport(final YangVersion version, final StatementSupport<?, ?, ?> definition) { Preconditions.checkNotNull(version); Preconditions.checkNotNull(definition); Preconditions.checkArgument(supportedVersions.contains(version)); final QName identifier = definition.getStatementName(); Preconditions.checkState(!commonStatements.containsKey(identifier), "Statement %s already defined in common statement bundle.", identifier); Preconditions.checkState(!versionSpecificStatements.contains(version, identifier), "Statement %s already defined for version %s.", identifier, version); Preconditions.checkState(parent.getCommonStatementDefinition(identifier) == null, "Statement %s already defined in parent's common statement bundle.", identifier); Preconditions.checkState(parent.getVersionSpecificStatementDefinition(version, identifier) == null, "Statement %s already defined for version %s in parent's statement bundle.", identifier, version); versionSpecificStatements.put(version, identifier, definition); return this; } public <K, V, N extends IdentifierNamespace<K, V>> Builder addSupport( final NamespaceBehaviour<K, V, N> namespaceSupport) { final Class<N> identifier = namespaceSupport.getIdentifier(); Preconditions.checkState(!namespaces.containsKey(identifier)); Preconditions.checkState(!parent.hasNamespaceBehaviour(identifier)); namespaces.put(identifier, namespaceSupport); return this; } public Set<YangVersion> getSupportedVersions() { return supportedVersions; } public Builder setParent(final StatementSupportBundle parent) { this.parent = parent; return this; } @Override public StatementSupportBundle build() { Preconditions.checkState(parent != null, "Parent must not be null"); return new StatementSupportBundle(parent, supportedVersions, ImmutableMap.copyOf(commonStatements), ImmutableMap.copyOf(namespaces), ImmutableTable.copyOf(versionSpecificStatements)); } } }