1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.util.xml;
16  
17  import com.liferay.util.xml.descriptor.XMLDescriptor;
18  
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.Vector;
24  
25  import org.dom4j.Document;
26  import org.dom4j.Element;
27  
28  /**
29   * <a href="XMLMerger.java.html"><b><i>View Source</i></b></a>
30   *
31   * @author Brian Wing Shun Chan
32   * @author Alan Zimmerman
33   * @author Jorge Ferrer
34   */
35  public class XMLMerger {
36  
37      public XMLMerger(XMLDescriptor descriptor) {
38          _descriptor = descriptor;
39      }
40  
41      public XMLElementComparator getElementComparator() {
42          return new XMLElementComparator(_descriptor);
43      }
44  
45      public Document merge(Document masterDoc, Document slaveDoc) {
46          Document mergedDoc = (Document)masterDoc.clone();
47  
48          Element root1 = mergedDoc.getRootElement();
49          Element root2 = slaveDoc.getRootElement();
50  
51          List<Element> children = root2.elements();
52  
53          for (Element el2 : children) {
54              Element el2Clone = (Element)el2.clone();
55  
56              el2Clone.detach();
57  
58              root1.add(el2Clone);
59          }
60  
61          organizeXML(mergedDoc);
62  
63          return mergedDoc;
64      }
65  
66      public void organizeXML(Document doc) {
67          Element root = doc.getRootElement();
68  
69          _orderChildren(root, _descriptor.getRootChildrenOrder());
70          _mergeDuplicateElements(root, getElementComparator());
71      }
72  
73      private void _addChildren(
74          Element first, Collection<Element> childrenToJoin) {
75  
76          Collection<Element> clones = new Vector<Element>();
77  
78          Iterator<Element> itr = childrenToJoin.iterator();
79  
80          while (itr.hasNext()) {
81              clones.add((Element)itr.next().clone());
82          }
83  
84          first.elements().addAll(clones);
85  
86          _orderChildren(first, _descriptor.getChildrenOrder(first));
87      }
88  
89      private boolean _containsObjectEqualTo(
90          Element example, List<Element> list, ElementComparator comparator) {
91  
92          Iterator<Element> itr = list.iterator();
93  
94          while (itr.hasNext()) {
95              Element candidate = itr.next();
96  
97              if (comparator.compare(example, candidate) == 0) {
98                  return true;
99              }
100         }
101 
102         return false;
103     }
104 
105     private Element _findObjectEqualTo(
106         Element example, List<Element> list, ElementComparator comparator) {
107 
108         Iterator<Element> itr = list.iterator();
109 
110         while (itr.hasNext()) {
111             Element candidate = itr.next();
112 
113             if (comparator.compare(example, candidate) == 0) {
114                 return candidate;
115             }
116         }
117 
118         return example;
119     }
120 
121     private void _mergeDuplicateElements(
122         Element el, ElementComparator comparator) {
123 
124         if (el.elements().size() > 0) {
125             List<Element> children = el.elements();
126 
127             List<Element> originals = new ArrayList<Element>();
128             List<Element> duplicates = new ArrayList<Element>();
129 
130             for (int i = 0; i < children.size(); i++) {
131                 Element child = children.get(i);
132 
133                 if (_containsObjectEqualTo(child, originals, comparator)) {
134                     if (_descriptor.canJoinChildren(child)) {
135                         Element first =
136                             _findObjectEqualTo(child, originals, comparator);
137 
138                         Collection<Element> childrenToJoin = child.elements();
139 
140                         _addChildren(first, childrenToJoin);
141                     }
142 
143                     duplicates.add(child);
144                 }
145                 else {
146                     originals.add(child);
147                 }
148             }
149 
150             for (Element duplicate : duplicates) {
151                 duplicate.detach();
152             }
153 
154             Iterator<Element> itr = originals.iterator();
155 
156             while (itr.hasNext()) {
157                 Element child = itr.next();
158 
159                 _mergeDuplicateElements(child, comparator);
160             }
161         }
162     }
163 
164     private void _orderChildren(
165         Element parent, String[] orderedChildrenNames) {
166 
167         if (orderedChildrenNames == null) {
168             return;
169         }
170 
171         List<Element> elements = new ArrayList<Element>();
172 
173         for (int i = 0; i < orderedChildrenNames.length; i++) {
174             elements.addAll(parent.elements(orderedChildrenNames[i]));
175         }
176 
177         for (Element el : elements) {
178             el.detach();
179 
180             parent.add(el);
181         }
182     }
183 
184     private XMLDescriptor _descriptor;
185 
186 }