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