View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.surefire.api.util.internal;
20  
21  import java.util.AbstractMap;
22  import java.util.LinkedHashSet;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import static java.util.Collections.unmodifiableSet;
27  
28  /**
29   * Copies input map in {@link #ImmutableMap(Map) constructor}, and Entries are linked and thread-safe.
30   * The map is immutable with linear list of entries.
31   *
32   * @param <K> key
33   * @param <V> value
34   * @since 2.20
35   */
36  public final class ImmutableMap<K, V> extends AbstractMap<K, V> {
37      private final Node<K, V> first;
38  
39      public ImmutableMap(Map<K, V> map) {
40          Node<K, V> first = null;
41          Node<K, V> previous = null;
42          for (Entry<K, V> e : map.entrySet()) {
43              Node<K, V> node = new Node<>(e.getKey(), e.getValue());
44              if (first == null) {
45                  first = node;
46              } else {
47                  previous.next = node;
48              }
49              previous = node;
50          }
51          this.first = first;
52      }
53  
54      @Override
55      public Set<Entry<K, V>> entrySet() {
56          Set<Entry<K, V>> entries = new LinkedHashSet<>();
57          Node<K, V> node = first;
58          while (node != null) {
59              entries.add(node);
60              node = node.next;
61          }
62          return unmodifiableSet(entries);
63      }
64  
65      static final class Node<K, V> implements Entry<K, V> {
66          final K key;
67          final V value;
68          volatile Node<K, V> next;
69  
70          Node(K key, V value) {
71              this.key = key;
72              this.value = value;
73          }
74  
75          @Override
76          public K getKey() {
77              return key;
78          }
79  
80          @Override
81          public V getValue() {
82              return value;
83          }
84  
85          @Override
86          public V setValue(V value) {
87              throw new UnsupportedOperationException();
88          }
89  
90          @Override
91          public boolean equals(Object o) {
92              if (this == o) {
93                  return true;
94              }
95  
96              if (o == null || getClass() != o.getClass()) {
97                  return false;
98              }
99  
100             Node<?, ?> node = (Node<?, ?>) o;
101 
102             return getKey() != null
103                     ? getKey().equals(node.getKey())
104                     : node.getKey() == null && getValue() != null
105                             ? getValue().equals(node.getValue())
106                             : node.getValue() == null;
107         }
108 
109         @Override
110         public int hashCode() {
111             int result = getKey() != null ? getKey().hashCode() : 0;
112             result = 31 * result + (getValue() != null ? getValue().hashCode() : 0);
113             return result;
114         }
115     }
116 }