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 children = root2.elements();
61  
62          for (int i = 0; i < children.size(); i++) {
63              Element el2 = (Element)children.get(i);
64  
65              Element el2Clone = (Element)el2.clone();
66  
67              el2Clone.detach();
68  
69              root1.add(el2Clone);
70          }
71  
72          organizeXML(mergedDoc);
73  
74          return mergedDoc;
75      }
76  
77      public void organizeXML(Document doc) {
78          Element root = doc.getRootElement();
79  
80          _orderChildren(root, _descriptor.getRootChildrenOrder());
81          _mergeDuplicateElements(root, getElementComparator());
82      }
83  
84      private void _addChildren(Element first, Collection childrenToJoin) {
85          Collection clones = new Vector();
86  
87          Iterator itr = childrenToJoin.iterator();
88  
89          while (itr.hasNext()) {
90              clones.add(((Element)itr.next()).clone());
91          }
92  
93          first.elements().addAll(clones);
94      }
95  
96      private boolean _containsObjectEqualTo(
97          Element example, List list, ElementComparator comparator) {
98  
99          Iterator itr = list.iterator();
100 
101         while (itr.hasNext()) {
102             Element candidate = (Element)itr.next();
103 
104             if (comparator.compare(example, candidate) == 0) {
105                 return true;
106             }
107         }
108 
109         return false;
110     }
111 
112     private Element _findObjectEqualTo(
113         Element example, List list, ElementComparator comparator) {
114 
115         Iterator itr = list.iterator();
116 
117         while (itr.hasNext()) {
118             Element candidate = (Element)itr.next();
119 
120             if (comparator.compare(example, candidate) == 0) {
121                 return candidate;
122             }
123         }
124 
125         return example;
126     }
127 
128     private void _mergeDuplicateElements(
129         Element el, ElementComparator comparator) {
130 
131         if (el.elements().size() > 0) {
132             List children = el.elements();
133 
134             List originals = new ArrayList();
135             List duplicates = new ArrayList();
136 
137             for (int i = 0; i < children.size(); i++) {
138                 Element child = (Element)children.get(i);
139 
140                 if (_containsObjectEqualTo(child, originals, comparator)) {
141                     if (_descriptor.canJoinChildren(child)) {
142                         Element first =
143                             _findObjectEqualTo(child, originals, comparator);
144 
145                         Collection childrenToJoin = child.elements();
146 
147                         _addChildren(first, childrenToJoin);
148                     }
149 
150                     duplicates.add(child);
151                 }
152                 else {
153                     originals.add(child);
154                 }
155             }
156 
157             for (int i = 0; i < duplicates.size(); i++) {
158                 Element duplicate = (Element)duplicates.get(i);
159 
160                 duplicate.detach();
161             }
162 
163             Iterator itr = originals.iterator();
164 
165             while (itr.hasNext()) {
166                 Element child = (Element)itr.next();
167 
168                 _mergeDuplicateElements(child, comparator);
169             }
170         }
171     }
172 
173     private void _orderChildren(
174         Element parent, String[] orderedChildrenNames) {
175 
176         if (orderedChildrenNames == null) {
177             return;
178         }
179 
180         List elements = new ArrayList();
181 
182         for (int i = 0; i < orderedChildrenNames.length; i++) {
183             elements.addAll(parent.elements(orderedChildrenNames[i]));
184         }
185 
186         for (int i = 0; i < elements.size(); i++) {
187             Element el = (Element)elements.get(i);
188             el.detach();
189             parent.add(el);
190         }
191     }
192 
193     private XMLDescriptor _descriptor;
194 
195 }