View Javadoc
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    *   http://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 io.netty.util.internal.ObjectUtil;
20  import io.netty.util.internal.PlatformDependent;
21  
22  import java.util.concurrent.ConcurrentMap;
23  import java.util.concurrent.atomic.AtomicInteger;
24  
25  /**
26   * A pool of {@link Constant}s.
27   *
28   * @param <T> the type of the constant
29   */
30  public abstract class ConstantPool<T extends Constant<T>> {
31  
32      private final ConcurrentMap<String, T> constants = PlatformDependent.newConcurrentHashMap();
33  
34      private final AtomicInteger nextId = new AtomicInteger(1);
35  
36      /**
37       * Shortcut of {@link #valueOf(String) valueOf(firstNameComponent.getName() + "#" + secondNameComponent)}.
38       */
39      public T valueOf(Class<?> firstNameComponent, String secondNameComponent) {
40          if (firstNameComponent == null) {
41              throw new NullPointerException("firstNameComponent");
42          }
43          if (secondNameComponent == null) {
44              throw new NullPointerException("secondNameComponent");
45          }
46  
47          return valueOf(firstNameComponent.getName() + '#' + secondNameComponent);
48      }
49  
50      /**
51       * Returns the {@link Constant} which is assigned to the specified {@code name}.
52       * If there's no such {@link Constant}, a new one will be created and returned.
53       * Once created, the subsequent calls with the same {@code name} will always return the previously created one
54       * (i.e. singleton.)
55       *
56       * @param name the name of the {@link Constant}
57       */
58      public T valueOf(String name) {
59          checkNotNullAndNotEmpty(name);
60          return getOrCreate(name);
61      }
62  
63      /**
64       * Get existing constant by name or creates new one if not exists. Threadsafe
65       *
66       * @param name the name of the {@link Constant}
67       */
68      private T getOrCreate(String name) {
69          T constant = constants.get(name);
70          if (constant == null) {
71              final T tempConstant = newConstant(nextId(), name);
72              constant = constants.putIfAbsent(name, tempConstant);
73              if (constant == null) {
74                  return tempConstant;
75              }
76          }
77  
78          return constant;
79      }
80  
81      /**
82       * Returns {@code true} if a {@link AttributeKey} exists for the given {@code name}.
83       */
84      public boolean exists(String name) {
85          checkNotNullAndNotEmpty(name);
86          return constants.containsKey(name);
87      }
88  
89      /**
90       * Creates a new {@link Constant} for the given {@code name} or fail with an
91       * {@link IllegalArgumentException} if a {@link Constant} for the given {@code name} exists.
92       */
93      public T newInstance(String name) {
94          checkNotNullAndNotEmpty(name);
95          return createOrThrow(name);
96      }
97  
98      /**
99       * Creates constant by name or throws exception. Threadsafe
100      *
101      * @param name the name of the {@link Constant}
102      */
103     private T createOrThrow(String name) {
104         T constant = constants.get(name);
105         if (constant == null) {
106             final T tempConstant = newConstant(nextId(), name);
107             constant = constants.putIfAbsent(name, tempConstant);
108             if (constant == null) {
109                 return tempConstant;
110             }
111         }
112 
113         throw new IllegalArgumentException(String.format("'%s' is already in use", name));
114     }
115 
116     private static String checkNotNullAndNotEmpty(String name) {
117         ObjectUtil.checkNotNull(name, "name");
118 
119         if (name.isEmpty()) {
120             throw new IllegalArgumentException("empty name");
121         }
122 
123         return name;
124     }
125 
126     protected abstract T newConstant(int id, String name);
127 
128     @Deprecated
129     public final int nextId() {
130         return nextId.getAndIncrement();
131     }
132 }