001    /*
002     * $RCSfile: MergeProperties.java,v $
003     * $Revision: 1.2 $ $Date: 2006/11/22 10:50:21 $
004     *
005     * This file is part of ***  M y C o R e  ***
006     * See http://www.mycore.de/ for details.
007     *
008     * This program is free software; you can use it, redistribute it
009     * and / or modify it under the terms of the GNU General Public License
010     * (GPL) as published by the Free Software Foundation; either version 2
011     * of the License or (at your option) any later version.
012     *
013     * This program is distributed in the hope that it will be useful, but
014     * WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program, in a file called gpl.txt or license.txt.
020     * If not, write to the Free Software Foundation Inc.,
021     * 59 Temple Place - Suite 330, Boston, MA  02111-1307 USA
022     */
023    package org.mycore.buildtools.anttasks;
024    
025    import java.io.File;
026    import java.io.FileInputStream;
027    import java.io.FileOutputStream;
028    import java.io.InputStreamReader;
029    import java.io.OutputStreamWriter;
030    import java.nio.channels.FileChannel;
031    import java.util.Arrays;
032    import java.util.HashSet;
033    import java.util.Set;
034    
035    import javax.xml.parsers.DocumentBuilder;
036    import javax.xml.parsers.DocumentBuilderFactory;
037    
038    import org.apache.tools.ant.BuildException;
039    import org.apache.tools.ant.Task;
040    import org.apache.xml.serialize.OutputFormat;
041    import org.apache.xml.serialize.XMLSerializer;
042    import org.w3c.dom.Document;
043    import org.w3c.dom.Element;
044    import org.w3c.dom.Node;
045    import org.w3c.dom.NodeList;
046    import org.xml.sax.InputSource;
047    
048    /**
049     * Ant task, that can be used to merges one searchfield.xml file into another.
050     * New indexes will be added. It depends on the boolean flag overwrite, if the
051     * paths and object types for existing indexes will be overwritten or
052     * concatenated .
053     * 
054     * @author Robert Stephan
055     * 
056     * @version $Revision: 13085 $ $Date: 2008-02-06 18:27:24 +0100 (Mi, 06 Feb
057     *          2008) $
058     * 
059     */
060    public class MCRMergeSearchfieldsXMLTask extends Task {
061            private String base, delta, out;
062            private boolean overwrite = false;
063    
064            /**
065             * set the base searchfield.xml file
066             * 
067             * @param f
068             *            the base searchfield.xml file
069             */
070            public void setBasefile(String f) {
071                    base = f;
072                    out = f;
073            }
074    
075            /**
076             * set the delta searchfield.xml file
077             * 
078             * @param f
079             *            the delta searchfield.xml file
080             */
081            public void setDeltafile(String f) {
082                    delta = f;
083            }
084    
085            /**
086             * sets the overwrite flag when set exisiting object type and path values
087             * will be overwritten
088             * 
089             * @param b
090             */
091            public void setOverwrite(boolean b) {
092                    overwrite = b;
093            }
094    
095            /*
096             * (non-Javadoc)
097             * 
098             * @see org.apache.tools.ant.Task#execute()
099             */
100            public void execute() throws BuildException {
101                    try {
102                            DocumentBuilderFactory factory = DocumentBuilderFactory
103                                            .newInstance();
104                            factory.setValidating(false);
105                            factory.setIgnoringElementContentWhitespace(true);
106                            DocumentBuilder builder = factory.newDocumentBuilder();
107                            Document docBase = builder.parse(new InputSource(
108                                            new InputStreamReader(new FileInputStream(new File(base)),
109                                                            "UTF-8")));
110                            docBase.normalize();
111    
112                            Document docDelta = builder.parse(new InputSource(
113                                            new InputStreamReader(new FileInputStream(new File(delta)),
114                                                            "UTF-8")));
115                            docDelta.normalize();
116    
117                            merge(docBase, docDelta);
118                            docBase.normalize();
119    
120                            // output
121                            // TransformerFactory tFactory = TransformerFactory.newInstance();
122                            // Transformer transformer = tFactory.newTransformer();
123                            // transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
124                            // transformer.setOutputProperty(OutputKeys.METHOD,"xml");
125                            // transformer.setOutputProperty(OutputKeys.INDENT, "true");
126                            // transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount",
127                            // "4");
128                            // DOMSource source = new DOMSource(docBase);
129                            // StreamResult result = new StreamResult(new FileOutputStream(new
130                            // File(out)));
131                            // transformer.transform(source, result);
132    
133                            // alternative code for output (with "pretty print")
134                            OutputFormat format = new OutputFormat(docBase);
135                            format.setLineWidth(360);
136                            format.setIndenting(true);
137                            format.setIndent(4);
138                            XMLSerializer serializer = new XMLSerializer(
139                                            new OutputStreamWriter(new FileOutputStream(new File(out)),
140                                                            "UTF-8"), format);
141                            serializer.serialize(docBase);
142    
143                    } catch (Exception e) {
144                            throw new BuildException(
145                                            "Something went wrong while merging searchfields!", e);
146                    }
147            }
148    
149            /**
150             * simple test case for the class
151             * @param args the default arguments for main method (unused)
152             */
153            public static void main(String[] args) {
154                    String basefile = "C:\\mycore\\modules\\buildtools\\test\\searchfields\\searchfields.org.xml";
155                    String deltafile = "C:\\mycore\\modules\\buildtools\\test\\searchfields\\othersearchfields.xml";
156                    String outfile = "C:\\mycore\\modules\\buildtools\\test\\searchfields\\searchfields.xml";
157    
158                    // copy the file;
159                    try {
160                            FileChannel ic = new FileInputStream(basefile).getChannel();
161                            FileChannel oc = new FileOutputStream(outfile).getChannel();
162                            ic.transferTo(0, ic.size(), oc);
163                            ic.close();
164                            oc.close();
165                    } catch (Exception e) {
166                            e.printStackTrace();
167                    }
168    
169                    MCRMergeSearchfieldsXMLTask mx = new MCRMergeSearchfieldsXMLTask();
170                    mx.setBasefile(outfile);
171                    mx.setDeltafile(deltafile);
172    
173                    mx.execute();
174                    System.out.println("OK");
175    
176            }
177    
178            private void merge(Document docBase, Document docDelta) {
179                    NodeList nlDeltaElemIndex = docDelta.getDocumentElement()
180                                    .getElementsByTagName("index");
181                    for (int i = 0; i < nlDeltaElemIndex.getLength(); i++) {
182                            Element eDeltaIndex = (Element) nlDeltaElemIndex.item(i);
183                            // System.out.println(eDeltaIndex.getAttribute("id"));
184                            Element eBaseIndex = findIndexElement(eDeltaIndex
185                                            .getAttribute("id"), docBase);
186                            mergeIndexElements(eBaseIndex, eDeltaIndex);
187                    }
188            }
189    
190            private Element findIndexElement(String id, Document doc) {
191                    NodeList nlElemIndex = doc.getDocumentElement().getElementsByTagName(
192                                    "index");
193                    for (int i = 0; i < nlElemIndex.getLength(); i++) {
194                            Element elem = (Element) nlElemIndex.item(i);
195                            if (elem.getAttribute("id").equals(id)) {
196                                    return elem;
197                            }
198                    }
199                    // Element has not been found -> create index element
200                    Element index = doc.createElement("index");
201                    index.setAttribute("id", id);
202                    doc.getDocumentElement().appendChild(index);
203                    return index;
204            }
205    
206            private void mergeIndexElements(Element eBaseIndex, Element eDeltaIndex) {
207                    NodeList nlDeltaElemField = eDeltaIndex.getElementsByTagName("field");
208                    for (int i = 0; i < nlDeltaElemField.getLength(); i++) {
209                            Element eDeltaField = (Element) nlDeltaElemField.item(i);
210                            // System.out.println("+--- "+ eDeltaField.getAttribute("name"));
211                            Element eBaseField = findFieldElement(eDeltaField
212                                            .getAttribute("name"), eBaseIndex);
213                            if (overwrite) {
214                                    overwriteField(eBaseField, eDeltaField);
215                            } else {
216                                    mergeField(eBaseField, eDeltaField);
217                            }
218                    }
219            }
220    
221            private Element findFieldElement(String name, Element eIndex) {
222                    NodeList nlElemField = eIndex.getElementsByTagName("field");
223                    for (int i = 0; i < nlElemField.getLength(); i++) {
224                            Element elem = (Element) nlElemField.item(i);
225                            if (elem.getAttribute("name").equals(name)) {
226                                    return elem;
227                            }
228                    }
229                    // Element has not been found -> create index element
230                    Element field = eIndex.getOwnerDocument().createElement("field");
231                    field.setAttribute("name", name);
232                    eIndex.appendChild(field);
233                    return field;
234            }
235    
236            private void mergeField(Element eBaseField, Element eDeltaField) {
237                    // attributes source and type must be equal
238                    if (!eBaseField.getAttribute("source").equals("")
239                                    && !eDeltaField.getAttribute("source").equals("")
240                                    && !eBaseField.getAttribute("source").equals(
241                                                    eDeltaField.getAttribute("source"))) {
242                            throw new BuildException("Attributes source of field "
243                                            + eBaseField.getAttribute("name")
244                                            + " must be equal to be merged!" + "\n   base file : "
245                                            + base + "\n   delta file: " + delta);
246                    }
247                    if (!eBaseField.getAttribute("type").equals("")
248                                    && !eDeltaField.getAttribute("type").equals("")
249                                    && !eBaseField.getAttribute("type").equals(
250                                                    eDeltaField.getAttribute("type"))) {
251                            throw new BuildException("Attributes type of field "
252                                            + eBaseField.getAttribute("name")
253                                            + " must be equal to be merged!" + "\n   base file : "
254                                            + base + "\n   delta file: " + delta);
255                    }
256                    // attribute objects (separated by space)
257                    if (!eDeltaField.getAttribute("objects").equals("")) {
258                            if (eBaseField.getAttribute("objects").trim().length() == 0) {
259                                    eBaseField.setAttribute("objects", eDeltaField
260                                                    .getAttribute("objects"));
261                            } else {
262                                    String data = (eBaseField.getAttribute("objects") + " " + eDeltaField
263                                                    .getAttribute("objects"));
264                                    Set<String> set = new HashSet<String>(Arrays.asList(data
265                                                    .split("\\s+")));
266                                    StringBuffer result = new StringBuffer();
267                                    for (String s : set) {
268                                            result.append(" ").append(s.trim());
269                                    }
270                                    eBaseField.setAttribute("objects", result.substring(1));
271                            }
272                    }
273                    // attribute: value (separated by "|")
274                    if (!eDeltaField.getAttribute("value").equals("")) {
275                            if (eBaseField.getAttribute("value").trim().length() == 0) {
276                                    eBaseField.setAttribute("value", eDeltaField
277                                                    .getAttribute("value"));
278                            } else {
279                                    String data = (eBaseField.getAttribute("value") + " | " + eDeltaField
280                                                    .getAttribute("value"));
281                                    Set<String> set = new HashSet<String>(Arrays.asList(data
282                                                    .split("\\s*\\|\\s*")));
283                                    StringBuffer result = new StringBuffer();
284                                    for (String s : set) {
285                                            result.append(" | ").append(s.trim());
286                                    }
287                                    eBaseField.setAttribute("value", result.substring(3));
288                            }
289                    }
290                    // attribute: xpath (separated by "|")
291                    if (!eDeltaField.getAttribute("xpath").equals("")) {
292                            if (eBaseField.getAttribute("xpath").trim().length() == 0) {
293                                    eBaseField.setAttribute("xpath", eDeltaField
294                                                    .getAttribute("xpath"));
295                            } else {
296                                    String data = (eBaseField.getAttribute("xpath") + " | " + eDeltaField
297                                                    .getAttribute("xpath"));
298                                    Set<String> set = new HashSet<String>(Arrays.asList(data
299                                                    .split("\\s*\\|\\s*")));
300                                    StringBuffer result = new StringBuffer();
301                                    for (String s : set) {
302                                            result.append(" | ").append(s.trim());
303                                    }
304                                    eBaseField.setAttribute("xpath", result.substring(3));
305                            }
306                    }
307    
308                    // attributes: sortable, classification, i18n (will be overwritten)
309                    if (!eDeltaField.getAttribute("sortable").equals("")) {
310                            eBaseField.setAttribute("sortable", eDeltaField
311                                            .getAttribute("sortable"));
312                    }
313                    if (!eDeltaField.getAttribute("i18n").equals("")) {
314                            eBaseField.setAttribute("i18n", eDeltaField.getAttribute("i18n"));
315                    }
316                    if (!eDeltaField.getAttribute("classification").equals("")) {
317                            eBaseField.setAttribute("classification", eDeltaField
318                                            .getAttribute("classification"));
319                    }
320            }
321    
322            private void overwriteField(Element eBaseField, Element eDeltaField) {
323                    Node newField = eBaseField.getOwnerDocument().importNode(eDeltaField,
324                                    true);
325                    eBaseField.getParentNode().replaceChild(newField, eBaseField);
326            }
327    }