001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.internal; 014 015import static java.util.Collections.*; 016import static java.util.stream.Collectors.*; 017 018import java.util.*; 019 020import org.apache.juneau.utils.*; 021 022/** 023 * A linked hashmap with reverse key lookup by value. 024 * 025 * @param <K> The key type. 026 * @param <V> The value type. 027 */ 028public class BiMap<K,V> implements Map<K,V> { 029 030 //----------------------------------------------------------------------------------------------------------------- 031 // Static 032 //----------------------------------------------------------------------------------------------------------------- 033 034 /** 035 * Create a new builder for this class. 036 * 037 * @param <K> The key type. 038 * @param <V> The value type. 039 * @return A new builder. 040 */ 041 public static <K,V> Builder<K,V> create() { 042 return new Builder<>(); 043 } 044 045 //----------------------------------------------------------------------------------------------------------------- 046 // Builder 047 //----------------------------------------------------------------------------------------------------------------- 048 049 /** 050 * Builder class. 051 * 052 * @param <K> The key type. 053 * @param <V> The value type. 054 */ 055 public static class Builder<K,V> { 056 final HashMap<K,V> map = new LinkedHashMap<>(); 057 boolean unmodifiable; 058 059 /** 060 * Adds a value to this map. 061 * 062 * @param key The key. 063 * @param value The value. 064 * @return This object. 065 */ 066 public Builder<K,V> add(K key, V value) { 067 map.put(key, value); 068 return this; 069 } 070 071 /** 072 * Makes this map unmodifiable. 073 * 074 * @return This object. 075 */ 076 public Builder<K,V> unmodifiable() { 077 unmodifiable = true; 078 return this; 079 } 080 081 /** 082 * Build the differences. 083 * 084 * @return A new {@link BeanDiff} object. 085 */ 086 public BiMap<K,V> build() { 087 return new BiMap<>(this); 088 } 089 090 } 091 092 //----------------------------------------------------------------------------------------------------------------- 093 // Instance 094 //----------------------------------------------------------------------------------------------------------------- 095 096 private final Map<K,V> forward; 097 private final Map<V,K> reverse; 098 099 /** 100 * Constructor. 101 * 102 * @param builder The builder for this object. 103 */ 104 public BiMap(Builder<K,V> builder) { 105 Map<K,V> forward = builder.map.entrySet().stream().filter(x -> x.getKey() != null && x.getValue() != null).collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); 106 Map<V,K> reverse = builder.map.entrySet().stream().filter(x -> x.getKey() != null && x.getValue() != null).collect(toMap(Map.Entry::getValue, Map.Entry::getKey)); 107 this.forward = builder.unmodifiable ? unmodifiableMap(forward) : forward; 108 this.reverse = builder.unmodifiable ? unmodifiableMap(reverse) : reverse; 109 } 110 111 /** 112 * Gets the key that is currently mapped to the specified value. 113 * 114 * @param value The value to return. 115 * @return The key matching the value. 116 */ 117 public K getKey(V value) { 118 return reverse.get(value); 119 } 120 121 122 @Override /* Map */ 123 public int size() { 124 return forward.size(); 125 } 126 127 @Override /* Map */ 128 public boolean isEmpty() { 129 return forward.isEmpty(); 130 } 131 132 @Override /* Map */ 133 public boolean containsKey(Object key) { 134 return forward.containsKey(key); 135 } 136 137 @Override /* Map */ 138 public boolean containsValue(Object value) { 139 return reverse.containsKey(value); 140 } 141 142 @Override /* Map */ 143 public V get(Object key) { 144 return forward.get(key); 145 } 146 147 @Override /* Map */ 148 public V put(K key, V value) { 149 reverse.put(value, key); 150 return forward.put(key, value); 151 } 152 153 @Override /* Map */ 154 public V remove(Object key) { 155 V value = forward.remove(key); 156 reverse.remove(value); 157 return value; 158 } 159 160 @Override /* Map */ 161 public void putAll(Map<? extends K,? extends V> m) { 162 forward.putAll(m); 163 m.entrySet().forEach(x -> reverse.put(x.getValue(), x.getKey())); 164 } 165 166 @Override /* Map */ 167 public void clear() { 168 forward.clear(); 169 reverse.clear(); 170 } 171 172 @Override /* Map */ 173 public Set<K> keySet() { 174 return forward.keySet(); 175 } 176 177 @Override /* Map */ 178 public Collection<V> values() { 179 return forward.values(); 180 } 181 182 @Override /* Map */ 183 public Set<Entry<K,V>> entrySet() { 184 return forward.entrySet(); 185 } 186}