View Javadoc

1   package org.apache.velocity.util;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.    
20   */
21  
22  import java.lang.reflect.Constructor;
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.Hashtable;
26  import java.util.Map;
27  
28  /**
29   * Factory class for creating Maps.
30   * 
31   * The main purpose of this class is to take advantage of Java 5
32   * Concurrent classes if they are available. We use reflection to instantiate
33   * java.util.concurrent classes to avoid compile time dependency on Java 5.
34   * 
35   * See <a href="http://issues.apache.org/jira/browse/VELOCITY-607">Issue 607</a>
36   * for more info on this class.
37   * @author <a href="mailto:wyla@sci.fi">Jarkko Viinamaki</a>
38   * @since 1.6
39   */
40  public class MapFactory
41  {
42      private static Constructor concurrentHashMapConstructor;
43      static
44      {
45          try
46          {
47              concurrentHashMapConstructor =
48                  Class.forName("java.util.concurrent.ConcurrentHashMap")
49                       .getConstructor(new Class[] { int.class, float.class, int.class } );
50          }
51          catch (Exception ex)
52          {
53              // not running under JRE 1.5+
54          }
55      }
56  
57      /**
58       * Creates a new instance of a class that implements Map interface
59       * using the JDK defaults for initial size, load factor, etc.
60       * 
61       * Note that there is a small performance penalty because concurrent
62       * maps are created using reflection.
63       * 
64       * @param allowNullKeys if true, the returned Map instance supports null keys         
65       * @return one of ConcurrentHashMap, HashMap, Hashtable
66       */
67      public static Map create(boolean allowNullKeys)
68      {
69          return create(16, 0.75f, 16, allowNullKeys);
70      }
71  
72      /**
73       * Creates a new instance of a class that implements Map interface.
74       * 
75       * Note that there is a small performance penalty because concurrent
76       * maps are created using reflection.
77       * 
78       * @param size initial size of the map
79       * @param loadFactor smaller value = better performance, 
80       *          larger value = better memory utilization
81       * @param concurrencyLevel estimated number of writer Threads. 
82       *          If this is smaller than 1, HashMap is always returned which is not 
83       *          threadsafe.
84       * @param allowNullKeys if true, the returned Map instance supports null keys         
85       *          
86       * @return one of ConcurrentHashMap, HashMap, Hashtable
87       */
88      public static Map create(int size, float loadFactor,
89                               int concurrencyLevel, boolean allowNullKeys)
90      {
91          Map map = null;
92          if (concurrencyLevel <= 1)
93          {
94              map = new HashMap(size, loadFactor);
95          }
96          else
97          {
98              if (concurrentHashMapConstructor != null)
99              {
100                 // running under JRE 1.5+
101                 try
102                 {
103                     map = (Map)concurrentHashMapConstructor.newInstance(
104                         new Object[] { new Integer(size), new Float(loadFactor), new Integer(concurrencyLevel) });
105                 }
106                 catch (Exception ex)
107                 {
108                     throw new RuntimeException("this should not happen", ex);
109                 }
110             }
111             else
112             {
113                 /*
114                  * Hashtable should be faster than
115                  * Collections.synchronizedMap(new HashMap());
116                  * so favor it if there is no need for null key support
117                  */
118                 if (allowNullKeys)
119                 {
120                     map = Collections.synchronizedMap(new HashMap(size, loadFactor));
121                 }
122                 else
123                 {
124                     map = new Hashtable(size, loadFactor);
125                 }
126             }
127         }
128         return map;
129     }
130 }