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