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 }