package org.dcache.util; import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import diskCacheV111.util.FsPath; /** * An object that maps path prefixes to values. In contrast to a * normal Map, the get operation of a PrefixMap returns the value of * the longest known prefix of a path. * * Definitions: A path, P_n, is a sequence of names, p_i for 1 <= i * <= n. Given two paths, P_n and Q_m, P_n is a prefix of Q_m iff * p_i=q_i for 1 <= i <= n. The string representation of a path * P_n is the concatenation of the elements in the sequence, prefixing * each element with a slash. * * Paths are internally normalized by removing empty elements, dot and * dot dot. */ public class PrefixMap<V> { private final Map<FsPath,V> _entries = new ConcurrentHashMap(); /** * Returns the number of prefixes stored in the PrefixMap. */ public int size() { return _entries.size(); } /** * Returns the set of prefix to value entries stored in the * map. The set is a backed by the PrefixMap, meaning that updates * to the PrefixMap are reflected in the set. The set is * unmodifiable. */ public Set<Map.Entry<FsPath,V>> entrySet() { return Collections.unmodifiableSet(_entries.entrySet()); } /** * Adds a prefix to value mapping. * * @throws IllegalArgumentException is either argument is null, or * if the prefix is empty or is not an absolute path. */ public void put(FsPath prefix, V value) { if (prefix == null || value == null) { throw new IllegalArgumentException("Null argument not allowed"); } _entries.put(prefix, value); } /** * Returns the value of the longest prefix of the path in the * PrefixMap. Returns null if such a longest prefix does not * exist. * * @throws IllegalArgumentException if path is null. */ public V get(FsPath path) { if (path == null) { throw new IllegalArgumentException("Null argument not allowed"); } V v = _entries.get(path); while (v == null && !path.isRoot()) { path = path.parent(); v = _entries.get(path); } return v; } }