1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.util.xml;
24  
25  import com.liferay.util.xml.descriptor.XMLDescriptor;
26  
27  import java.util.ArrayList;
28  import java.util.Collection;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Vector;
32  
33  import org.dom4j.Document;
34  import org.dom4j.Element;
35  
36  /**
37   * <a href="XMLMerger.java.html"><b><i>View Source</i></b></a>
38   *
39   * @author Brian Wing Shun Chan
40   * @author Alan Zimmerman
41   * @author Jorge Ferrer
42   *
43   */
44  public class XMLMerger {
45  
46      public XMLMerger(XMLDescriptor descriptor) {
47          _descriptor = descriptor;
48      }
49  
50      public XMLElementComparator getElementComparator() {
51          return new XMLElementComparator(_descriptor);
52      }
53  
54      public Document merge(Document masterDoc, Document slaveDoc) {
55          Document mergedDoc = (Document)masterDoc.clone();
56  
57          Element root1 = mergedDoc.getRootElement();
58          Element root2 = slaveDoc.getRootElement();
59  
60          List<Element> children = root2.elements();
61  
62          for (Element el2 : children) {
63              Element el2Clone = (Element)el2.clone();
64  
65              el2Clone.detach();
66  
67              root1.add(el2Clone);
68          }
69  
70          organizeXML(mergedDoc);
71  
72          return mergedDoc;
73      }
74  
75      public void organizeXML(Document doc) {
76          Element root = doc.getRootElement();
77  
78          _orderChildren(root, _descriptor.getRootChildrenOrder());
79          _mergeDuplicateElements(root, getElementComparator());
80      }
81  
82      private void _addChildren(Element first, Collection childrenToJoin) {
83          Collection clones = new Vector();
84  
85          Iterator itr = childrenToJoin.iterator();
86  
87          while (itr.hasNext()) {
88              clones.add(((Element)itr.next()).clone());
89          }
90  
91          first.elements().addAll(clones);
92      }
93  
94      private boolean _containsObjectEqualTo(
95          Element example, List list, ElementComparator comparator) {
96  
97          Iterator itr = list.iterator();
98  
99          while (itr.hasNext()) {
100             Element candidate = (Element)itr.next();
101 
102             if (comparator.compare(example, candidate) == 0) {
103                 return true;
104             }
105         }
106 
107         return false;
108     }
109 
110     private Element _findObjectEqualTo(
111         Element example, List list, ElementComparator comparator) {
112 
113         Iterator itr = list.iterator();
114 
115         while (itr.hasNext()) {
116             Element candidate = (Element)itr.next();
117 
118             if (comparator.compare(example, candidate) == 0) {
119                 return candidate;
120             }
121         }
122 
123         return example;
124     }
125 
126     private void _mergeDuplicateElements(
127         Element el, ElementComparator comparator) {
128 
129         if (el.elements().size() > 0) {
130             List children = el.elements();
131 
132             List originals = new ArrayList();
133             List duplicates = new ArrayList();
134 
135             for (int i = 0; i < children.size(); i++) {
136                 Element child = (Element)children.get(i);
137 
138                 if (_containsObjectEqualTo(child, originals, comparator)) {
139                     if (_descriptor.canJoinChildren(child)) {
140                         Element first =
141                             _findObjectEqualTo(child, originals, comparator);
142 
143                         Collection childrenToJoin = child.elements();
144 
145                         _addChildren(first, childrenToJoin);
146                     }
147 
148                     duplicates.add(child);
149                 }
150                 else {
151                     originals.add(child);
152                 }
153             }
154 
155             for (int i = 0; i < duplicates.size(); i++) {
156                 Element duplicate = (Element)duplicates.get(i);
157 
158                 duplicate.detach();
159             }
160 
161             Iterator itr = originals.iterator();
162 
163             while (itr.hasNext()) {
164                 Element child = (Element)itr.next();
165 
166                 _mergeDuplicateElements(child, comparator);
167             }
168         }
169     }
170 
171     private void _orderChildren(
172         Element parent, String[] orderedChildrenNames) {
173 
174         if (orderedChildrenNames == null) {
175             return;
176         }
177 
178         List elements = new ArrayList();
179 
180         for (int i = 0; i < orderedChildrenNames.length; i++) {
181             elements.addAll(parent.elements(orderedChildrenNames[i]));
182         }
183 
184         for (int i = 0; i < elements.size(); i++) {
185             Element el = (Element)elements.get(i);
186             el.detach();
187             parent.add(el);
188         }
189     }
190 
191     private XMLDescriptor _descriptor;
192 
193 }