1/*
2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3 */
4/*
5 * Licensed to the Apache Software Foundation (ASF) under one or more
6 * contributor license agreements.  See the NOTICE file distributed with
7 * this work for additional information regarding copyright ownership.
8 * The ASF licenses this file to You under the Apache License, Version 2.0
9 * (the "License"); you may not use this file except in compliance with
10 * the License.  You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20/*
21 * $Id: MultiHashtable.java,v 1.2.4.1 2005/09/05 11:18:51 pvedula Exp $
22 */
23
24package com.sun.org.apache.xalan.internal.xsltc.compiler.util;
25
26import java.util.HashMap;
27import java.util.HashSet;
28import java.util.Map;
29import java.util.Set;
30
31/**
32 * @author Jacek Ambroziak
33 * @author Santiago Pericas-Geertsen
34 * @param <K>
35 * @param <V>
36 */
37public final class MultiHashtable<K,V> {
38    static final long serialVersionUID = -6151608290510033572L;
39
40    private final Map<K, Set<V>> map = new HashMap<>();
41    private boolean modifiable = true;
42
43    /**
44     * Associates the specified key with a set of values. If the map previously
45     * contained a mapping for the key, the value is added to the set.
46     * @param key key with which the specified value is to be associated
47     * @param value value to be added to a set that is associated with the specified key
48     * @return the set that is associated with the specified key.
49     * @throw UnsupportedOperationException is the MultiHashtable is not modifiable.
50     */
51    public Set<V> put(K key, V value) {
52        if (modifiable) {
53            Set<V> set = map.computeIfAbsent(key, k -> new HashSet<>());
54            set.add(value);
55            return set;
56        }
57        throw new UnsupportedOperationException("The MultiHashtable instance is not modifiable.");
58    }
59
60    /**
61     * Maps a key to a value in a set that is associated with the specified key.
62     * The mapping is performed by evaluating whether an item in the set equals
63     * the specified value.
64     *
65     * @param key key with which the specified value is to be associated
66     * @param value value in a set that is associated with the specified key
67     * @return the item in the set if a match is found.
68     */
69    public V maps(K key, V value) {
70        if (key == null) return null;
71        final Set<V> set = map.get(key);
72        if (set != null) {
73            for (V v : set) {
74                if (v.equals(value)) {
75                    return v;
76                }
77            }
78        }
79        return null;
80    }
81
82    /**
83     * Makes the MultiHashtable unmodifiable.  This method allows modules to set the table
84     * as "read-only" so that only query operation, that is maps, is allowed. Any attempts
85     * to modify the returned map result in an UnsupportedOperationException.
86     */
87    public void makeUnmodifiable() {
88        modifiable = false;
89    }
90}
91