1 /*
2 * Copyright 2013 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16
17 package io.netty.util;
18
19 import static io.netty.util.internal.ObjectUtil.checkNotNull;
20 import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
21
22 import java.util.concurrent.ConcurrentHashMap;
23 import java.util.concurrent.ConcurrentMap;
24 import java.util.concurrent.atomic.AtomicInteger;
25
26 /**
27 * A pool of {@link Constant}s.
28 *
29 * @param <T> the type of the constant
30 */
31 public abstract class ConstantPool<T extends Constant<T>> {
32
33 private final ConcurrentMap<String, T> constants = new ConcurrentHashMap<>();
34
35 private final AtomicInteger nextId = new AtomicInteger(1);
36
37 /**
38 * Shortcut of {@link #valueOf(String) valueOf(firstNameComponent.getName() + "#" + secondNameComponent)}.
39 */
40 public T valueOf(Class<?> firstNameComponent, String secondNameComponent) {
41 return valueOf(
42 checkNotNull(firstNameComponent, "firstNameComponent").getName() +
43 '#' +
44 checkNotNull(secondNameComponent, "secondNameComponent"));
45 }
46
47 /**
48 * Returns the {@link Constant} which is assigned to the specified {@code name}.
49 * If there's no such {@link Constant}, a new one will be created and returned.
50 * Once created, the subsequent calls with the same {@code name} will always return the previously created one
51 * (i.e. singleton.)
52 *
53 * @param name the name of the {@link Constant}
54 */
55 public T valueOf(String name) {
56 return getOrCreate(checkNonEmpty(name, "name"));
57 }
58
59 /**
60 * Get existing constant by name or creates new one if not exists. Threadsafe
61 *
62 * @param name the name of the {@link Constant}
63 */
64 private T getOrCreate(String name) {
65 T constant = constants.get(name);
66 if (constant == null) {
67 final T tempConstant = newConstant(nextId(), name);
68 constant = constants.putIfAbsent(name, tempConstant);
69 if (constant == null) {
70 return tempConstant;
71 }
72 }
73
74 return constant;
75 }
76
77 /**
78 * Returns {@code true} if a {@link AttributeKey} exists for the given {@code name}.
79 */
80 public boolean exists(String name) {
81 return constants.containsKey(checkNonEmpty(name, "name"));
82 }
83
84 /**
85 * Creates a new {@link Constant} for the given {@code name} or fail with an
86 * {@link IllegalArgumentException} if a {@link Constant} for the given {@code name} exists.
87 */
88 public T newInstance(String name) {
89 return createOrThrow(checkNonEmpty(name, "name"));
90 }
91
92 /**
93 * Creates constant by name or throws exception. Threadsafe
94 *
95 * @param name the name of the {@link Constant}
96 */
97 private T createOrThrow(String name) {
98 T constant = constants.get(name);
99 if (constant == null) {
100 final T tempConstant = newConstant(nextId(), name);
101 constant = constants.putIfAbsent(name, tempConstant);
102 if (constant == null) {
103 return tempConstant;
104 }
105 }
106
107 throw new IllegalArgumentException(String.format("'%s' is already in use", name));
108 }
109
110 protected abstract T newConstant(int id, String name);
111
112 @Deprecated
113 public final int nextId() {
114 return nextId.getAndIncrement();
115 }
116 }