1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.util;
18
19 import java.util.Collections;
20 import java.util.LinkedHashMap;
21 import java.util.Map;
22 import java.util.Set;
23
24 import static io.netty.util.internal.ObjectUtil.checkNotNull;
25
26
27
28
29
30
31 public final class DomainNameMappingBuilder<V> {
32
33 private final V defaultValue;
34 private final Map<String, V> map;
35
36
37
38
39
40
41
42 public DomainNameMappingBuilder(V defaultValue) {
43 this(4, defaultValue);
44 }
45
46
47
48
49
50
51
52
53 public DomainNameMappingBuilder(int initialCapacity, V defaultValue) {
54 this.defaultValue = checkNotNull(defaultValue, "defaultValue");
55 map = new LinkedHashMap<String, V>(initialCapacity);
56 }
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public DomainNameMappingBuilder<V> add(String hostname, V output) {
71 map.put(checkNotNull(hostname, "hostname"), checkNotNull(output, "output"));
72 return this;
73 }
74
75
76
77
78
79
80
81 public DomainNameMapping<V> build() {
82 return new ImmutableDomainNameMapping<V>(defaultValue, map);
83 }
84
85
86
87
88
89
90
91 private static final class ImmutableDomainNameMapping<V> extends DomainNameMapping<V> {
92 private static final String REPR_HEADER = "ImmutableDomainNameMapping(default: ";
93 private static final String REPR_MAP_OPENING = ", map: {";
94 private static final String REPR_MAP_CLOSING = "})";
95 private static final int REPR_CONST_PART_LENGTH =
96 REPR_HEADER.length() + REPR_MAP_OPENING.length() + REPR_MAP_CLOSING.length();
97
98 private final String[] domainNamePatterns;
99 private final V[] values;
100 private final Map<String, V> map;
101
102 @SuppressWarnings("unchecked")
103 private ImmutableDomainNameMapping(V defaultValue, Map<String, V> map) {
104 super(null, defaultValue);
105
106 Set<Map.Entry<String, V>> mappings = map.entrySet();
107 int numberOfMappings = mappings.size();
108 domainNamePatterns = new String[numberOfMappings];
109 values = (V[]) new Object[numberOfMappings];
110
111 final Map<String, V> mapCopy = new LinkedHashMap<String, V>(map.size());
112 int index = 0;
113 for (Map.Entry<String, V> mapping : mappings) {
114 final String hostname = normalizeHostname(mapping.getKey());
115 final V value = mapping.getValue();
116 domainNamePatterns[index] = hostname;
117 values[index] = value;
118 mapCopy.put(hostname, value);
119 ++index;
120 }
121
122 this.map = Collections.unmodifiableMap(mapCopy);
123 }
124
125 @Override
126 @Deprecated
127 public DomainNameMapping<V> add(String hostname, V output) {
128 throw new UnsupportedOperationException(
129 "Immutable DomainNameMapping does not support modification after initial creation");
130 }
131
132 @Override
133 public V map(String hostname) {
134 if (hostname != null) {
135 hostname = normalizeHostname(hostname);
136
137 int length = domainNamePatterns.length;
138 for (int index = 0; index < length; ++index) {
139 if (matches(domainNamePatterns[index], hostname)) {
140 return values[index];
141 }
142 }
143 }
144
145 return defaultValue;
146 }
147
148 @Override
149 public Map<String, V> asMap() {
150 return map;
151 }
152
153 @Override
154 public String toString() {
155 String defaultValueStr = defaultValue.toString();
156
157 int numberOfMappings = domainNamePatterns.length;
158 if (numberOfMappings == 0) {
159 return REPR_HEADER + defaultValueStr + REPR_MAP_OPENING + REPR_MAP_CLOSING;
160 }
161
162 String pattern0 = domainNamePatterns[0];
163 String value0 = values[0].toString();
164 int oneMappingLength = pattern0.length() + value0.length() + 3;
165 int estimatedBufferSize = estimateBufferSize(defaultValueStr.length(), numberOfMappings, oneMappingLength);
166
167 StringBuilder sb = new StringBuilder(estimatedBufferSize)
168 .append(REPR_HEADER).append(defaultValueStr).append(REPR_MAP_OPENING);
169
170 appendMapping(sb, pattern0, value0);
171 for (int index = 1; index < numberOfMappings; ++index) {
172 sb.append(", ");
173 appendMapping(sb, index);
174 }
175
176 return sb.append(REPR_MAP_CLOSING).toString();
177 }
178
179
180
181
182
183
184
185
186
187
188
189 private static int estimateBufferSize(int defaultValueLength,
190 int numberOfMappings,
191 int estimatedMappingLength) {
192 return REPR_CONST_PART_LENGTH + defaultValueLength
193 + (int) (estimatedMappingLength * numberOfMappings * 1.10);
194 }
195
196 private StringBuilder appendMapping(StringBuilder sb, int mappingIndex) {
197 return appendMapping(sb, domainNamePatterns[mappingIndex], values[mappingIndex].toString());
198 }
199
200 private static StringBuilder appendMapping(StringBuilder sb, String domainNamePattern, String value) {
201 return sb.append(domainNamePattern).append('=').append(value);
202 }
203 }
204 }