KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencms > setup > xml > CmsSetupXmlHelper


1 /*
2  * File : $Source: /usr/local/cvs/opencms/src/org/opencms/setup/xml/CmsSetupXmlHelper.java,v $
3  * Date : $Date: 2006/04/28 15:20:52 $
4  * Version: $Revision: 1.3 $
5  *
6  * This library is part of OpenCms -
7  * the Open Source Content Mananagement System
8  *
9  * Copyright (c) 2005 Alkacon Software GmbH (http://www.alkacon.com)
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * For further information about Alkacon Software GmbH, please see the
22  * company website: http://www.alkacon.com
23  *
24  * For further information about OpenCms, please see the
25  * project website: http://www.opencms.org
26  *
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30  */

31
32 package org.opencms.setup.xml;
33
34 import org.opencms.i18n.CmsEncoder;
35 import org.opencms.i18n.CmsMessageContainer;
36 import org.opencms.main.CmsLog;
37 import org.opencms.util.CmsStringUtil;
38 import org.opencms.xml.CmsXmlException;
39 import org.opencms.xml.CmsXmlUtils;
40
41 import java.io.File JavaDoc;
42 import java.io.FileNotFoundException JavaDoc;
43 import java.io.FileOutputStream JavaDoc;
44 import java.io.FileReader JavaDoc;
45 import java.io.OutputStream JavaDoc;
46 import java.io.StringReader JavaDoc;
47 import java.util.ArrayList JavaDoc;
48 import java.util.HashMap JavaDoc;
49 import java.util.Iterator JavaDoc;
50 import java.util.Map JavaDoc;
51
52 import org.apache.commons.logging.Log;
53
54 import org.dom4j.Document;
55 import org.dom4j.Element;
56 import org.dom4j.Node;
57 import org.xml.sax.EntityResolver JavaDoc;
58 import org.xml.sax.InputSource JavaDoc;
59
60 /**
61  * Helper class to modify xml files.<p>
62  *
63  * For more info about xpath see: <br>
64  * <ul>
65  * <li>http://www.w3.org/TR/xpath.html</li>
66  * <li>http://www.zvon.org/xxl/XPathTutorial/General/examples.html</li>
67  * </ul><p>
68  *
69  * @author Michael Moossen
70  *
71  * @version $Revision: 1.3 $
72  *
73  * @since 6.1.8
74  */

75 public class CmsSetupXmlHelper {
76
77     /** Entity resolver to skip dtd validation. */
78     private static final EntityResolver JavaDoc NO_ENTITY_RESOLVER = new EntityResolver JavaDoc() {
79
80         /**
81          * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String)
82          */

83         public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId) {
84
85             return new InputSource JavaDoc(new StringReader JavaDoc(""));
86         }
87     };
88
89     /** Optional base path. */
90     private String JavaDoc m_basePath = null;
91
92     /** Document cache. */
93     private Map JavaDoc m_cache = new HashMap JavaDoc();
94
95     /**
96      * Default constructor.<p>
97      *
98      * Uses no base path.<p>
99      */

100     public CmsSetupXmlHelper() {
101
102         // ignore
103
}
104
105     /**
106      * Uses an optional base file path.<p>
107      *
108      * @param basePath the base file path to use;
109      */

110     public CmsSetupXmlHelper(String JavaDoc basePath) {
111
112         m_basePath = basePath;
113     }
114
115     /**
116      * Unmarshals (reads) an XML string into a new document.<p>
117      *
118      * @param xml the XML code to unmarshal
119      *
120      * @return the generated document
121      *
122      * @throws CmsXmlException if something goes wrong
123      */

124     public static String JavaDoc format(String JavaDoc xml) throws CmsXmlException {
125
126         return CmsXmlUtils.marshal((Node)CmsXmlUtils.unmarshalHelper(xml, null), CmsEncoder.ENCODING_UTF_8);
127     }
128
129     /**
130      * Returns the value in the given xpath of the given xml file.<p>
131      *
132      * @param document the xml document
133      * @param xPath the xpath to read (should select a single node or attribute)
134      *
135      * @return the value in the given xpath of the given xml file, or <code>null</code> if no matching node
136      */

137     public static String JavaDoc getValue(Document document, String JavaDoc xPath) {
138
139         Node node = document.selectSingleNode(xPath);
140         if (node != null) {
141             // return the value
142
return node.getText();
143         } else {
144             return null;
145         }
146     }
147
148     /** The log object for this class. */
149     private static final Log LOG = CmsLog.getLog(CmsSetupXmlHelper.class);
150
151     /**
152      * Sets the given value in all nodes identified by the given xpath of the given xml file.<p>
153      *
154      * If value is <code>null</code>, all nodes identified by the given xpath will be deleted.<p>
155      *
156      * If the node identified by the given xpath does not exists, the missing nodes will be created
157      * (if <code>value</code> not <code>null</code>).<p>
158      *
159      * @param document the xml document
160      * @param xPath the xpath to set
161      * @param value the value to set (can be <code>null</code> for deletion)
162      *
163      * @return the number of successful changed or deleted nodes
164      */

165     public static int setValue(Document document, String JavaDoc xPath, String JavaDoc value) {
166
167         int changes = 0;
168         // be naive and try to find the node
169
Iterator JavaDoc itNodes = document.selectNodes(xPath).iterator();
170
171         // if not found
172
if (!itNodes.hasNext()) {
173             if (value == null) {
174                 // if no node found for deletion
175
return 0;
176             }
177             // find the node creating missing nodes in the way
178
Iterator JavaDoc it = CmsStringUtil.splitAsList(xPath, "/", false).iterator();
179             Node currentNode = document;
180             while (it.hasNext()) {
181                 String JavaDoc nodeName = (String JavaDoc)it.next();
182                 // if a string condition contains '/'
183
while (nodeName.indexOf("='") > 0 && nodeName.indexOf("']") < 0) {
184                     nodeName += "/" + (String JavaDoc)it.next();
185                 }
186                 Node node = currentNode.selectSingleNode(nodeName);
187                 if (node != null) {
188                     // node found
189
currentNode = node;
190                     if (!it.hasNext()) {
191                         currentNode.setText(value);
192                     }
193                 } else if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
194                     Element elem = (Element)currentNode;
195                     if (!nodeName.startsWith("@")) {
196                         // if node is no attribute, create a new node
197
String JavaDoc childName = null;
198                         String JavaDoc childValue = "";
199                         int pos = nodeName.indexOf("[");
200                         if (pos > 0) {
201                             // handle child node
202
int pos2 = nodeName.indexOf("=\'", pos);
203                             if (pos2 > 0) {
204                                 childName = nodeName.substring(pos + 1, pos2);
205                                 childValue = nodeName.substring(pos2 + 2, nodeName.indexOf('\'', pos2 + 2));
206                             }
207                             nodeName = nodeName.substring(0, pos);
208                         }
209                         // create node
210
elem = elem.addElement(nodeName);
211                         if (childName != null) {
212                             // create child node
213
if (childName.startsWith("@")) {
214                                 elem.addAttribute(childName.substring(1), childValue);
215                             } else {
216                                 Element child = elem.addElement(childName);
217                                 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(childValue)) {
218                                     child.addText(childValue);
219                                 }
220                             }
221                         }
222                         if (!it.hasNext()) {
223                             elem.setText(value);
224                         }
225                     } else {
226                         // if node is attribute create it with given value
227
elem.addAttribute(nodeName.substring(1), value);
228                     }
229                     currentNode = elem;
230                 } else {
231                     // should never happen
232
if (LOG.isDebugEnabled()) {
233                         LOG.debug(Messages.get().getBundle().key(Messages.ERR_XML_SET_VALUE_2, xPath, value));
234                     }
235                     break;
236                 }
237             }
238             return 1;
239         }
240
241         // if found
242
while (itNodes.hasNext()) {
243             Node node = (Node)itNodes.next();
244             if (value != null) {
245                 // if found, change the value
246
node.setText(value);
247             } else {
248                 // if node for deletion is found
249
node.getParent().remove(node);
250             }
251             changes++;
252         }
253         return changes;
254     }
255
256     /**
257      * Discards the changes in the given file.<p>
258      *
259      * @param xmlFilename the xml config file (could be relative to the base path)
260      */

261     public void flush(String JavaDoc xmlFilename) {
262
263         m_cache.remove(xmlFilename);
264     }
265
266     /**
267      * Discards the changes in all files.<p>
268      */

269     public void flushAll() {
270
271         m_cache.clear();
272     }
273
274     /**
275      * Returns the base file Path.<p>
276      *
277      * @return the base file Path
278      */

279     public String JavaDoc getBasePath() {
280
281         return m_basePath;
282     }
283
284     /**
285      * Returns the document for the given filename.<p>
286      * It can be new read or come from the document cache.<p>
287      *
288      * @param xmlFilename the filename to read
289      *
290      * @return the document for the given filename
291      *
292      * @throws CmsXmlException if something goes wrong while reading
293      */

294     public Document getDocument(String JavaDoc xmlFilename) throws CmsXmlException {
295
296         // try to get it from the cache
297
Document document = (Document)m_cache.get(xmlFilename);
298
299         if (document == null) {
300             try {
301                 document = CmsXmlUtils.unmarshalHelper(
302                     new InputSource JavaDoc(new FileReader JavaDoc(getFile(xmlFilename))),
303                     NO_ENTITY_RESOLVER);
304             } catch (FileNotFoundException JavaDoc e) {
305                 throw new CmsXmlException(new CmsMessageContainer(null, e.toString()));
306             }
307             // cache the doc
308
m_cache.put(xmlFilename, document);
309         }
310         return document;
311     }
312
313     /**
314      * Returns the value in the given xpath of the given xml file.<p>
315      *
316      * @param xmlFilename the xml config file (could be relative to the base path)
317      * @param xPath the xpath to read (should select a single node or attribute)
318      *
319      * @return the value in the given xpath of the given xml file, or <code>null</code> if no matching node
320      *
321      * @throws CmsXmlException if something goes wrong while reading
322      */

323     public String JavaDoc getValue(String JavaDoc xmlFilename, String JavaDoc xPath) throws CmsXmlException {
324
325         return getValue(getDocument(xmlFilename), xPath);
326     }
327
328     /**
329      * Sets the given value in all nodes identified by the given xpath of the given xml file.<p>
330      *
331      * If value is <code>null</code>, all nodes identified by the given xpath will be deleted.<p>
332      *
333      * If the node identified by the given xpath does not exists, the missing nodes will be created
334      * (if <code>value</code> not <code>null</code>).<p>
335      *
336      * @param xmlFilename the xml config file (could be relative to the base path)
337      * @param xPath the xpath to set
338      * @param value the value to set (can be <code>null</code> for deletion)
339      *
340      * @return the number of successful changed or deleted nodes
341      *
342      * @throws CmsXmlException if something goes wrong
343      */

344     public int setValue(String JavaDoc xmlFilename, String JavaDoc xPath, String JavaDoc value) throws CmsXmlException {
345
346         return setValue(getDocument(xmlFilename), xPath, value);
347     }
348
349     /**
350      * Writes the given file back to disk.<p>
351      *
352      * @param xmlFilename the xml config file (could be relative to the base path)
353      *
354      * @throws CmsXmlException if something wrong while writing
355      */

356     public void write(String JavaDoc xmlFilename) throws CmsXmlException {
357
358         // try to get it from the cache
359
Document document = (Document)m_cache.get(xmlFilename);
360
361         if (document != null) {
362             try {
363                 OutputStream JavaDoc out = new FileOutputStream JavaDoc(getFile(xmlFilename));
364                 CmsXmlUtils.marshal(document, out, CmsEncoder.ENCODING_UTF_8);
365             } catch (FileNotFoundException JavaDoc e) {
366                 throw new CmsXmlException(new CmsMessageContainer(null, e.toString()));
367             }
368         }
369     }
370
371     /**
372      * Flushes all cached documents.<p>
373      *
374      * @throws CmsXmlException if something wrong while writing
375      */

376     public void writeAll() throws CmsXmlException {
377
378         Iterator JavaDoc it = new ArrayList JavaDoc(m_cache.keySet()).iterator();
379         while (it.hasNext()) {
380             String JavaDoc filename = (String JavaDoc)it.next();
381             write(filename);
382         }
383     }
384
385     /**
386      * Returns a file from a given filename.<p>
387      *
388      * @param xmlFilename the file name
389      *
390      * @return the file
391      */

392     private File JavaDoc getFile(String JavaDoc xmlFilename) {
393
394         File JavaDoc file = new File JavaDoc(m_basePath + xmlFilename);
395         if (!file.exists() || !file.canRead()) {
396             file = new File JavaDoc(xmlFilename);
397         }
398         return file;
399     }
400 }
Popular Tags