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