001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.util;
029
030import java.util.Collections;
031import java.util.Map;
032import java.util.Set;
033
034import com.google.common.collect.HashMultimap;
035import com.google.common.collect.Maps;
036import com.google.common.collect.Multimap;
037import com.google.common.collect.Multimaps;
038
039/**
040 * Special collection class which allows lookup from keys to values  and from values to sets of keys.<p>
041 *
042 * It also  implements efficient removal of values, not just keys.<p>
043 *
044 * @param <K> the key type
045 * @param <V> the value type
046 */
047public class CmsManyToOneMap<K, V> {
048
049    /** Map from keys to values . */
050    private Map<K, V> m_forwardMap = Maps.newHashMap();
051
052    /** Map from values to sets of keys. */
053    private HashMultimap<V, K> m_reverseMap = HashMultimap.create();
054
055    /**
056     * Creates a new instance.<p>
057     */
058    public CmsManyToOneMap() {
059
060        // do nothing
061    }
062
063    /**
064     * Creates a new instance by copying the data from another one.<p>
065     *
066     * @param other the other map to copy the data from
067     */
068    public CmsManyToOneMap(CmsManyToOneMap<K, V> other) {
069
070        for (Map.Entry<K, V> entry : other.getForwardMap().entrySet()) {
071            put(entry.getKey(), entry.getValue());
072        }
073    }
074
075    /**
076     * Gets the value for a key.<p>
077     *
078     * @param key the key
079     * @return the value for the key, or null
080     */
081    public V get(K key) {
082
083        return m_forwardMap.get(key);
084    }
085
086    /**
087     * Associates a value with a key.<p>
088     *
089     * @param key the key
090     * @param value the value
091     */
092    public void put(K key, V value) {
093
094        m_forwardMap.put(key, value);
095        m_reverseMap.put(value, key);
096
097    }
098
099    /**
100     * Removes the entry with the given key.<p>
101     *
102     * @param key the key
103     */
104    public void remove(K key) {
105
106        V removedValue = m_forwardMap.remove(key);
107        if (removedValue != null) {
108            m_reverseMap.remove(removedValue, key);
109        }
110    }
111
112    /**
113     * Removes all entries with the given value.<p>
114     *
115     * @param value the value
116     */
117    public void removeValue(V value) {
118
119        Set<K> keys = m_reverseMap.removeAll(value);
120        for (K key : keys) {
121            m_forwardMap.remove(key);
122        }
123    }
124
125    /**
126     * Gets the (immutable) map from keys to values.
127     *
128     * @return the map from keys to values
129     */
130    Map<K, V> getForwardMap() {
131
132        return Collections.unmodifiableMap(m_forwardMap);
133    }
134
135    /**
136     * Gets the multimap from values to keys.<p>
137     *
138     * @return the multimap from values to keys
139     */
140    Multimap<V, K> getReverseMap() {
141
142        return Multimaps.unmodifiableSetMultimap(m_reverseMap);
143    }
144}