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       * 
60       * Note that there is a small performance penalty because concurrent
61       * maps are created using reflection.
62       * 
63       * @param size initial size of the map
64       * @param loadFactor smaller value = better performance, 
65       *          larger value = better memory utilization
66       * @param concurrencyLevel estimated number of writer Threads. 
67       *          If this is smaller than 1, HashMap is always returned which is not 
68       *          threadsafe.
69       * @param allowNullKeys if true, the returned Map instance supports null keys         
70       *          
71       * @return one of ConcurrentHashMap, HashMap, Hashtable
72       */
73      public static Map create(int size, float loadFactor,
74                               int concurrencyLevel, boolean allowNullKeys)
75      {
76          Map map = null;
77          if (concurrencyLevel <= 1)
78          {
79              map = new HashMap(size, loadFactor);
80          }
81          else
82          {
83              if (concurrentHashMapConstructor != null)
84              {
85                  // running under JRE 1.5+
86                  try
87                  {
88                      map = (Map)concurrentHashMapConstructor.newInstance(
89                          new Object[] { new Integer(size), new Float(loadFactor), new Integer(concurrencyLevel) });
90                  }
91                  catch (Exception ex)
92                  {
93                      throw new RuntimeException("this should not happen", ex);
94                  }
95              }
96              else
97              {
98                  /*
99                   * Hashtable should be faster than
100                  * Collections.synchronizedMap(new HashMap());
101                  * so favor it if there is no need for null key support
102                  */
103                 if (allowNullKeys)
104                 {
105                     map = Collections.synchronizedMap(new HashMap(size, loadFactor));
106                 }
107                 else
108                 {
109                     map = new Hashtable(size, loadFactor);
110                 }
111             }
112         }
113         return map;
114     }
115 }