/* * 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 java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.model.api.meta.IdentifierNamespace; /** * Definition / implementation of specific Identifier Namespace behaviour. * * Namespace behaviour is build on top of tree of {@link NamespaceStorageNode} which represents local context of one of * types defined in {@link StorageNodeType}. * * For common behaviour models please use static factories {@link #global(Class)}, {@link #sourceLocal(Class)} and * {@link #treeScoped(Class)}. * * @param * Key type * @param * Value type * @param * Namespace Type */ public abstract class NamespaceBehaviour> implements Identifiable> { public enum StorageNodeType { GLOBAL, SOURCE_LOCAL_SPECIAL, STATEMENT_LOCAL, ROOT_STATEMENT_LOCAL } public interface Registry { > NamespaceBehaviour getNamespaceBehaviour(Class type); } public interface NamespaceStorageNode { /** * @return local namespace behaviour type {@link NamespaceBehaviour} */ StorageNodeType getStorageNodeType(); @Nullable NamespaceStorageNode getParentNamespaceStorage(); @Nullable > V getFromLocalStorage(Class type, K key); @Nullable > Map getAllFromLocalStorage(Class type); /** * Populate specified namespace with a key/value pair, overwriting previous contents. Similar to * {@link Map#put(Object, Object)}. * * @param type Namespace identifier * @param key Key * @param value Value * @return Previously-stored value, or null if the key was not present */ @Nullable > V putToLocalStorage(Class type, K key, V value); /** * Populate specified namespace with a key/value pair unless the key is already associated with a value. Similar * to {@link Map#putIfAbsent(Object, Object)}. * * @param type Namespace identifier * @param key Key * @param value Value * @return Preexisting value or null if there was no previous mapping */ @Nullable > V putToLocalStorageIfAbsent(Class type, K key, V value); } private final Class identifier; protected NamespaceBehaviour(final Class identifier) { this.identifier = Preconditions.checkNotNull(identifier); } /** * * Creates global namespace behaviour for supplied namespace type. * * Global behaviour stores and loads all values from root {@link NamespaceStorageNode} with type of * {@link StorageNodeType#GLOBAL}. * * @param identifier * Namespace identifier. * @param type parameter * @param type parameter * @param type parameter * * @return global namespace behaviour for supplied namespace type. */ public static @Nonnull > NamespaceBehaviour global( final Class identifier) { return new StorageSpecific<>(identifier, StorageNodeType.GLOBAL); } /** * * Creates source-local namespace behaviour for supplied namespace type. * * Source-local namespace behaviour stores and loads all values from closest {@link NamespaceStorageNode} ancestor * with type of {@link StorageNodeType#SOURCE_LOCAL_SPECIAL}. * * @param identifier * Namespace identifier. * @param type parameter * @param type parameter * @param type parameter * * @return source-local namespace behaviour for supplied namespace type. */ public static > NamespaceBehaviour sourceLocal( final Class identifier) { return new StorageSpecific<>(identifier, StorageNodeType.SOURCE_LOCAL_SPECIAL); } public static > NamespaceBehaviour statementLocal( final Class identifier) { return new StorageSpecific<>(identifier, StorageNodeType.STATEMENT_LOCAL); } /** * * Creates tree-scoped namespace behaviour for supplied namespace type. * * Tree-scoped namespace behaviour search for value in all storage nodes up to the root and stores values in * supplied node. * * @param identifier * Namespace identifier. * * @param type parameter * @param type parameter * @param type parameter * * @return tree-scoped namespace behaviour for supplied namespace type. */ public static > NamespaceBehaviour treeScoped(final Class identifier) { return new TreeScoped<>(identifier); } /** * returns value from model namespace storage according to key param class * * @param storage namespace storage * @param key type parameter * * @return value from model namespace storage according to key param class */ public abstract V getFrom(NamespaceStorageNode storage, K key); /** * returns all values of a keys of param class from model namespace storage * * @param storage namespace storage * * @return all values of keys of param class from model namespace storage */ public abstract Map getAllFrom(NamespaceStorageNode storage); /** * adds key and value to corresponding namespace storage according to param class * * @param storage namespace storage * @param key type parameter * @param value type parameter */ public abstract void addTo(NamespaceStorageNode storage, K key, V value); @Override public Class getIdentifier() { return identifier; } protected final V getFromLocalStorage(final NamespaceStorageNode storage, final K key) { return storage.getFromLocalStorage(getIdentifier(), key); } protected final Map getAllFromLocalStorage(final NamespaceStorageNode storage) { return storage.getAllFromLocalStorage(getIdentifier()); } protected final void addToStorage(final NamespaceStorageNode storage, final K key, final V value) { storage.putToLocalStorage(getIdentifier(), key, value); } static class StorageSpecific> extends NamespaceBehaviour { StorageNodeType storageType; public StorageSpecific(final Class identifier, final StorageNodeType type) { super(identifier); storageType = Preconditions.checkNotNull(type); } @Override public V getFrom(final NamespaceStorageNode storage, final K key) { NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType); return getFromLocalStorage(current, key); } @Override public Map getAllFrom(final NamespaceStorageNode storage) { NamespaceStorageNode current = storage; while (current.getStorageNodeType() != storageType) { current = current.getParentNamespaceStorage(); } return getAllFromLocalStorage(current); } @Override public void addTo(final NamespaceBehaviour.NamespaceStorageNode storage, final K key, final V value) { NamespaceStorageNode current = findClosestTowardsRoot(storage, storageType); addToStorage(current, key, value); } } static class TreeScoped> extends NamespaceBehaviour { public TreeScoped(final Class identifier) { super(identifier); } @Override public V getFrom(final NamespaceStorageNode storage, final K key) { NamespaceStorageNode current = storage; while (current != null) { final V val = getFromLocalStorage(current, key); if (val != null) { return val; } current = current.getParentNamespaceStorage(); } return null; } @Override public Map getAllFrom(final NamespaceStorageNode storage) { NamespaceStorageNode current = storage; while (current != null) { final Map val = getAllFromLocalStorage(current); if (val != null) { return val; } current = current.getParentNamespaceStorage(); } return null; } @Override public void addTo(final NamespaceStorageNode storage, final K key, final V value) { addToStorage(storage, key, value); } } protected static NamespaceStorageNode findClosestTowardsRoot(final NamespaceStorageNode storage, final StorageNodeType type) { NamespaceStorageNode current = storage; while (current != null && current.getStorageNodeType() != type) { current = current.getParentNamespaceStorage(); } return current; } }