1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package ch.elca.el4j.services.xmlmerge.action;
18
19 import java.util.ArrayList;
20 import java.util.LinkedHashMap;
21 import java.util.List;
22
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25 import org.jdom.Attribute;
26 import org.jdom.Comment;
27 import org.jdom.Content;
28 import org.jdom.Element;
29 import org.jdom.Text;
30
31 import ch.elca.el4j.services.xmlmerge.AbstractXmlMergeException;
32 import ch.elca.el4j.services.xmlmerge.Action;
33 import ch.elca.el4j.services.xmlmerge.DocumentException;
34 import ch.elca.el4j.services.xmlmerge.Mapper;
35 import ch.elca.el4j.services.xmlmerge.Matcher;
36 import ch.elca.el4j.services.xmlmerge.MergeAction;
37
38
39
40
41
42
43
44
45
46
47 public class OrderedMergeAction extends AbstractMergeAction {
48
49
50
51
52 private static Logger s_logger
53 = LoggerFactory.getLogger(OrderedMergeAction.class);
54
55
56
57
58 public void perform(Element originalElement, Element patchElement,
59 Element outputParentElement) throws AbstractXmlMergeException {
60
61 s_logger.debug("Merging: " + originalElement + "(List 1) and "
62 + patchElement + "(List 2)");
63
64 Mapper mapper = (Mapper) m_mapperFactory.getOperation(originalElement,
65 patchElement);
66
67 if (originalElement == null) {
68 outputParentElement.addContent(mapper.map(patchElement));
69 } else if (patchElement == null) {
70 outputParentElement.addContent((Content) originalElement.clone());
71 } else {
72
73 Element workingElement = new Element(originalElement.getName(),
74 originalElement.getNamespacePrefix(), originalElement
75 .getNamespaceURI());
76 addAttributes(workingElement, originalElement);
77
78 s_logger.debug("Adding " + workingElement);
79 outputParentElement.addContent(workingElement);
80
81 doIt(workingElement, originalElement, patchElement);
82 }
83
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97
98 private void doIt(Element parentOut, Element parentIn1, Element parentIn2)
99 throws AbstractXmlMergeException {
100
101 addAttributes(parentOut, parentIn2);
102
103 Content[] list1 = (Content[]) parentIn1.getContent().toArray(
104 new Content[] {});
105 Content[] list2 = (Content[]) parentIn2.getContent().toArray(
106 new Content[] {});
107
108 int offsetTreated1 = 0;
109 int offsetTreated2 = 0;
110
111 for (int i = 0; i < list1.length; i++) {
112
113 s_logger.debug("List 1: " + list1[i]);
114
115 if (list1[i] instanceof Comment || list1[i] instanceof Text) {
116 parentOut.addContent((Content) list1[i].clone());
117 offsetTreated1++;
118 } else if (!(list1[i] instanceof Element)) {
119 throw new DocumentException(list1[i].getDocument(),
120 "Contents of type " + list1[i].getClass().getName()
121 + " not supported");
122 } else {
123 Element e1 = (Element) list1[i];
124
125
126 int posInList2 = -1;
127 for (int j = offsetTreated2; j < list2.length; j++) {
128
129 s_logger.debug("List 2: " + list2[j]);
130
131 if (list2[j] instanceof Element) {
132
133 if (((Matcher) m_matcherFactory.getOperation(e1,
134 (Element) list2[j]))
135 .matches(e1, (Element) list2[j])) {
136 s_logger.debug("Match found: " + e1 + " and "
137 + list2[j]);
138 posInList2 = j;
139 break;
140 }
141 } else if (list2[j] instanceof Comment
142 || list2[j] instanceof Text) {
143
144 } else {
145 throw new DocumentException(list2[j].getDocument(),
146 "Contents of type " + list2[j].getClass().getName()
147 + " not supported");
148 }
149 }
150
151
152
153
154 while (posInList2 != -1 && offsetTreated2 < posInList2) {
155 Content contentToAdd;
156 if (list2[offsetTreated2] instanceof Element) {
157 applyAction(parentOut, null,
158 (Element) list2[offsetTreated2]);
159 } else {
160 contentToAdd = (Content) list2[offsetTreated2].clone();
161 parentOut.addContent(contentToAdd);
162 }
163
164 offsetTreated2++;
165 }
166
167
168 if (posInList2 != -1) {
169
170 applyAction(parentOut, (Element) list1[offsetTreated1],
171 (Element) list2[offsetTreated2]);
172
173 offsetTreated1++;
174 offsetTreated2++;
175 } else {
176
177 applyAction(parentOut, (Element) list1[offsetTreated1],
178 null);
179 offsetTreated1++;
180 }
181 }
182 }
183
184
185
186 while (offsetTreated2 < list2.length) {
187 Content contentToAdd;
188 if (list2[offsetTreated2] instanceof Element) {
189 applyAction(parentOut, null, (Element) list2[offsetTreated2]);
190 } else {
191 contentToAdd = (Content) list2[offsetTreated2].clone();
192 parentOut.addContent(contentToAdd);
193 }
194
195 offsetTreated2++;
196 }
197
198 }
199
200
201
202
203
204
205
206
207
208
209
210
211
212 private void applyAction(Element workingParent, Element originalElement,
213 Element patchElement) throws AbstractXmlMergeException {
214 Action action = (Action) m_actionFactory.getOperation(originalElement,
215 patchElement);
216 Mapper mapper = (Mapper) m_mapperFactory.getOperation(originalElement,
217 patchElement);
218
219
220
221 if (action instanceof MergeAction) {
222 MergeAction mergeAction = (MergeAction) action;
223 mergeAction.setActionFactory(m_actionFactory);
224 mergeAction.setMapperFactory(m_mapperFactory);
225 mergeAction.setMatcherFactory(m_matcherFactory);
226 }
227
228 action
229 .perform(originalElement, mapper.map(patchElement), workingParent);
230 }
231
232
233
234
235
236
237 private void addAttributes(Element out, Element in) {
238
239 LinkedHashMap allAttributes = new LinkedHashMap();
240
241 List outAttributes = new ArrayList(out.getAttributes());
242 List inAttributes = new ArrayList(in.getAttributes());
243
244 for (int i = 0; i < outAttributes.size(); i++) {
245 Attribute attr = (Attribute) outAttributes.get(i);
246 attr.detach();
247 allAttributes.put(attr.getQualifiedName(), attr);
248 s_logger.debug("adding attr from out:" + attr);
249 }
250
251 for (int i = 0; i < inAttributes.size(); i++) {
252 Attribute attr = (Attribute) inAttributes.get(i);
253 attr.detach();
254 allAttributes.put(attr.getQualifiedName(), attr);
255 s_logger.debug("adding attr from in:" + attr);
256 }
257
258 out.setAttributes(new ArrayList(allAttributes.values()));
259 }
260
261 }