1
2
3
4
5
6
7
8
9
10
11 package org.mule.util;
12
13 import java.util.Collection;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Set;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22
23
24
25
26
27
28 public class MapCombiner implements Map
29 {
30
31 public static final String LIST = "list";
32 public static final int UNLIMITED_DEPTH = -1;
33
34 private Log logger = LogFactory.getLog(getClass());
35 private int maxDepth = UNLIMITED_DEPTH;
36 private List list;
37 private Map cachedMerge = new HashMap();
38 private boolean isMerged = false;
39
40 private synchronized Map getCachedMerge()
41 {
42 if (!isMerged)
43 {
44 for (Iterator maps = list.iterator(); maps.hasNext();)
45 {
46 mergeMaps(maxDepth, cachedMerge, (Map) maps.next());
47 }
48 isMerged = true;
49 }
50 return cachedMerge;
51 }
52
53 public void setMaxDepth(int maxDepth)
54 {
55 this.maxDepth = maxDepth;
56 }
57
58 private void mergeMaps(int headroom, Map accumulator, Map extra)
59 {
60 for (Iterator keys = extra.keySet().iterator(); keys.hasNext();)
61 {
62 Object key = keys.next();
63 Object valueExtra = extra.get(key);
64 if (accumulator.containsKey(key))
65 {
66 Object valueOriginal = accumulator.get(key);
67 if (valueExtra instanceof Map && valueOriginal instanceof Map && headroom != 0)
68 {
69 mergeMaps(headroom - 1, (Map) valueOriginal, (Map) valueExtra);
70 }
71 else if (valueExtra instanceof Collection && valueOriginal instanceof Collection && headroom != 0)
72 {
73 ((Collection) valueOriginal).addAll((Collection) valueExtra);
74 }
75 else
76 {
77 if (logger.isDebugEnabled())
78 {
79 logger.debug("Overwriting " + valueOriginal + " for " + key + " during map merge");
80 }
81 accumulator.put(key, valueExtra);
82 }
83 }
84 else
85 {
86 accumulator.put(key, valueExtra);
87 }
88 }
89 }
90
91 public void setList(List list)
92 {
93 assertNotMerged();
94 this.list = list;
95 }
96
97 public List getList()
98 {
99 assertNotMerged();
100 return list;
101 }
102
103 private synchronized void assertNotMerged()
104 {
105 if (isMerged)
106 {
107 throw new IllegalStateException("Maps have already been merged");
108 }
109 }
110
111
112
113 public int hashCode()
114 {
115 return cachedMerge.hashCode();
116 }
117
118 public boolean equals(Object o)
119 {
120 return cachedMerge.equals(o);
121 }
122
123 public String toString()
124 {
125 if (isMerged)
126 {
127 return "merged: " + cachedMerge.toString();
128 }
129 else
130 {
131 return "unmerged: " + (null == list ? null : list.toString());
132 }
133 }
134
135 public int size()
136 {
137 return getCachedMerge().size();
138 }
139
140 public void clear()
141 {
142 getCachedMerge().clear();
143 }
144
145 public boolean isEmpty()
146 {
147 return getCachedMerge().isEmpty();
148 }
149
150 public boolean containsKey(Object key)
151 {
152 return getCachedMerge().containsKey(key);
153 }
154
155 public boolean containsValue(Object value)
156 {
157 return getCachedMerge().containsValue(value);
158 }
159
160 public Collection values()
161 {
162 return getCachedMerge().values();
163 }
164
165 public void putAll(Map t)
166 {
167 getCachedMerge().putAll(t);
168 }
169
170 public Set entrySet()
171 {
172 return getCachedMerge().entrySet();
173 }
174
175 public Set keySet()
176 {
177 return getCachedMerge().keySet();
178 }
179
180 public Object get(Object key)
181 {
182 return getCachedMerge().get(key);
183 }
184
185 public Object remove(Object key)
186 {
187 return getCachedMerge().remove(key);
188 }
189
190 public Object put(Object key, Object value)
191 {
192 return getCachedMerge().put(key, value);
193 }
194
195 }