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 }