KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > jmx > examples > scandir > config > XmlConfigUtils


1 /*
2  * XmlConfigUtils.java
3  *
4  * Created on July 13, 2006, 3:52 PM
5  *
6  * @(#)XmlConfigUtils.java 1.2 06/08/02
7  *
8  * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * -Redistribution of source code must retain the above copyright notice, this
14  * list of conditions and the following disclaimer.
15  *
16  * -Redistribution in binary form must reproduce the above copyright notice,
17  * this list of conditions and the following disclaimer in the documentation
18  * and/or other materials provided with the distribution.
19  *
20  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
21  * be used to endorse or promote products derived from this software without
22  * specific prior written permission.
23  *
24  * This software is provided "AS IS," without a warranty of any kind. ALL
25  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
26  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
27  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
28  * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
29  * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
30  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
31  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
32  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
33  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
34  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
35  *
36  * You acknowledge that this software is not designed, licensed or intended
37  * for use in the design, construction, operation or maintenance of any
38  * nuclear facility.
39  */

40
41 package com.sun.jmx.examples.scandir.config;
42
43 import java.io.ByteArrayInputStream JavaDoc;
44 import java.io.ByteArrayOutputStream JavaDoc;
45 import java.io.File JavaDoc;
46 import java.io.FileOutputStream JavaDoc;
47 import java.io.IOException JavaDoc;
48 import java.io.InputStream JavaDoc;
49 import java.io.OutputStream JavaDoc;
50 import java.util.logging.Logger JavaDoc;
51 import javax.xml.bind.JAXBContext;
52 import javax.xml.bind.JAXBException;
53 import javax.xml.bind.Marshaller;
54 import javax.xml.bind.Unmarshaller;
55
56 /**
57  * The class XmlConfigUtils is used to deal with XML serialization
58  * and XML files.
59  *
60  * @author Sun Microsystems, 2006 - All rights reserved.
61  */

62 public class XmlConfigUtils {
63     
64     /**
65      * A URI for our XML configuration namespace. This doesn't start with
66      * http:// because we are not going to publish this private schema
67      * anywhere.
68      **/

69     public static final String JavaDoc NAMESPACE =
70             "jmx:com.sun.jmx.examples.scandir.config";
71     /**
72      * A logger for this class.
73      **/

74     private static final Logger JavaDoc LOG =
75             Logger.getLogger(XmlConfigUtils.class.getName());
76
77     // Our JAXBContext.
78
private static JAXBContext context;
79     
80     // The file name of the XML file in which an instance of this object
81
// will read and write XML data.
82
final String JavaDoc file;
83     
84     /**
85      * Creates a new instance of XmlConfigUtils.
86      * @param file The file name of the XML file in which an instance of this
87      * object will read and write XML data.
88      */

89     public XmlConfigUtils(String JavaDoc file) {
90         this.file = file;
91     }
92
93     /**
94      * Write the given bean to the XML file.
95      * <p>
96      * Performs an atomic write, first writing in {@code <file>.new}, then
97      * renaming {@code <file>} to {@code <file>~}, then renaming
98      * renaming {@code <file>.new} to {@code <file>}.
99      * </p>
100      * @param bean The configuration to write in the XML file.
101      * @throws IOException if write to file failed.
102      **/

103     public synchronized void writeToFile(ScanManagerConfig bean)
104         throws IOException JavaDoc {
105         
106         // Creates a new file named <file>.new
107
final File JavaDoc f = newXmlTmpFile(file);
108         try {
109             final FileOutputStream JavaDoc out = new FileOutputStream JavaDoc(f);
110             boolean failed = true;
111             try {
112                 // writes to <file>.new
113
write(bean,out,false);
114                 
115                 // no exception: set failed=false for finaly {} block.
116
failed = false;
117             } finally {
118                 out.close();
119                 // An exception was raised: delete temporary file.
120
if (failed == true) f.delete();
121             }
122             
123             // rename <file> to <file>~ and <file>.new to <file>
124
commit(file,f);
125         } catch (JAXBException x) {
126             final IOException JavaDoc io =
127                     new IOException JavaDoc("Failed to write SessionConfigBean to " +
128                     file+": "+x,x);
129             throw io;
130         }
131     }
132     
133     /**
134      * Creates an XML string representation of the given bean.
135      * @throws IllegalArgumentException if the bean class is not known by the
136      * underlying XMLbinding context.
137      * @return An XML string representation of the given bean.
138      **/

139     public static String JavaDoc toString(Object JavaDoc bean) {
140         try {
141             final ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
142             final Marshaller m = createMarshaller();
143             m.setProperty(m.JAXB_FRAGMENT,Boolean.TRUE);
144             m.marshal(bean, baos);
145             return baos.toString();
146         } catch (JAXBException x) {
147             final IllegalArgumentException JavaDoc iae =
148                     new IllegalArgumentException JavaDoc(
149                         "Failed to write SessionConfigBean: "+x,x);
150             throw iae;
151         }
152     }
153     
154     /**
155      * Creates an XML clone of the given bean.
156      * <p>
157      * In other words, this method XML-serializes the given bean, and
158      * XML-deserializes a copy of that bean.
159      * </p>
160      * @return A deep-clone of the given bean.
161      * @throws IllegalArgumentException if the bean class is not known by the
162      * underlying XML binding context.
163      * @param bean The bean to clone.
164      */

165     public static ScanManagerConfig xmlClone(ScanManagerConfig bean) {
166         final Object JavaDoc clone = copy(bean);
167         return (ScanManagerConfig)clone;
168     }
169     
170     /**
171      * Creates an XML clone of the given bean.
172      * <p>
173      * In other words, this method XML-serializes the given bean, and
174      * XML-deserializes a copy of that bean.
175      * </p>
176      * @throws IllegalArgumentException if the bean class is not known by the
177      * underlying XML binding context.
178      * @return A deep-clone of the given bean.
179      **/

180     private static Object JavaDoc copy(Object JavaDoc bean) {
181         try {
182             final ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
183             final Marshaller m = createMarshaller();
184             m.marshal(bean, baos);
185             final ByteArrayInputStream JavaDoc bais =
186                     new ByteArrayInputStream JavaDoc(baos.toByteArray());
187             return createUnmarshaller().unmarshal(bais);
188         } catch (JAXBException x) {
189             final IllegalArgumentException JavaDoc iae =
190                     new IllegalArgumentException JavaDoc("Failed to write SessionConfigBean: "+x,x);
191             throw iae;
192         }
193     }
194    
195     /**
196      * Creates an XML clone of the given bean.
197      * <p>
198      * In other words, this method XML-serializes the given bean, and
199      * XML-deserializes a copy of that bean.
200      * </p>
201      * @return A deep-clone of the given bean.
202      * @throws IllegalArgumentException if the bean class is not known by the
203      * underlying XML binding context.
204      * @param bean The bean to clone.
205      */

206     public static DirectoryScannerConfig xmlClone(DirectoryScannerConfig bean) {
207         final Object JavaDoc clone = copy(bean);
208         return (DirectoryScannerConfig)clone;
209     }
210
211     /**
212      * Reads the configuration from the XML configuration file.
213      * @throws IOException if it fails to read the configuration.
214      * @return A {@code ScanManagerConfig} bean read from the
215      * XML configuration file.
216      **/

217     public synchronized ScanManagerConfig readFromFile() throws IOException JavaDoc {
218         final File JavaDoc f = new File JavaDoc(file);
219         if (!f.exists())
220             throw new IOException JavaDoc("No such file: "+file);
221         if (!f.canRead())
222             throw new IOException JavaDoc("Can't read file: "+file);
223         try {
224             return read(f);
225         } catch (JAXBException x) {
226             final IOException JavaDoc io =
227                     new IOException JavaDoc("Failed to read SessionConfigBean from " +
228                     file+": "+x,x);
229             throw io;
230         }
231     }
232
233     /**
234      * Reads the configuration from the given XML configuration file.
235      * @param f the file to read from.
236      * @return A {@code ScanManagerConfig} bean read from the
237      * XML configuration file.
238      * @throws javax.xml.bind.JAXBException if it fails to read the configuration.
239      */

240     public static ScanManagerConfig read(File JavaDoc f)
241         throws JAXBException {
242         final Unmarshaller u = createUnmarshaller();
243         return (ScanManagerConfig) u.unmarshal(f);
244         
245     }
246         
247     /**
248      * Writes the given bean to the given output stream.
249      * @param bean the bean to write.
250      * @param os the output stream to write to.
251      * @param fragment whether the {@code <?xml ... ?>} header should be
252      * included. The header is not included if the bean is just an
253      * XML fragment encapsulated in a higher level XML element.
254      * @throws JAXBException An XML Binding exception occurred.
255      **/

256     public static void write(ScanManagerConfig bean, OutputStream JavaDoc os,
257             boolean fragment)
258         throws JAXBException {
259         writeXml((Object JavaDoc)bean,os,fragment);
260     }
261     
262     /**
263      * Writes the given bean to the given output stream.
264      * @param bean the bean to write.
265      * @param os the output stream to write to.
266      * @param fragment whether the {@code <?xml ... ?>} header should be
267      * included. The header is not included if the bean is just an
268      * XML fragment encapsulated in a higher level XML element.
269      * @throws JAXBException An XML Binding exception occurred.
270      **/

271     public static void write(ResultRecord bean, OutputStream JavaDoc os, boolean fragment)
272         throws JAXBException {
273         writeXml((Object JavaDoc)bean,os,fragment);
274     }
275     
276     /**
277      * Writes the given bean to the given output stream.
278      * @param bean the bean to write.
279      * @param os the output stream to write to.
280      * @param fragment whether the {@code <?xml ... ?>} header should be
281      * included. The header is not included if the bean is just an
282      * XML fragment encapsulated in a higher level XML element.
283      * @throws JAXBException An XML Binding exception occurred.
284      **/

285     private static void writeXml(Object JavaDoc bean, OutputStream JavaDoc os, boolean fragment)
286         throws JAXBException {
287         final Marshaller m = createMarshaller();
288         if (fragment) m.setProperty(m.JAXB_FRAGMENT,Boolean.TRUE);
289         m.marshal(bean,os);
290     }
291     
292     // Creates a JAXB Unmarshaller.
293
private static Unmarshaller createUnmarshaller() throws JAXBException {
294         return getContext().createUnmarshaller();
295     }
296     
297     // Creates a JAXB Marshaller - for nicely XML formatted output.
298
private static Marshaller createMarshaller() throws JAXBException {
299         final Marshaller m = getContext().createMarshaller();
300         m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,Boolean.TRUE);
301         return m;
302     }
303     
304     // Creates a JAXBContext if needed, and returns it.
305
// The JAXBContext instance we create will be able to handle the
306
// ScanManagerConfig and ResultRecord classes, plus all the property
307
// classes they reference (DirectoryScannerBean etc...).
308
//
309
private static synchronized JAXBContext getContext() throws JAXBException {
310         if (context == null)
311             context = JAXBContext.newInstance(ScanManagerConfig.class,
312                                               ResultRecord.class);
313         return context;
314     }
315
316
317     // Creates a new XML temporary file called <basename>.new
318
// This method is used to implement atomic writing to file.
319
// The usual sequence is:
320
//
321
// Final tmp = newXmlTmpFile(basename);
322
// boolean failed = true;
323
// try {
324
// ... write to 'tmp' ...
325
// // no exception: set failed=false for finaly {} block.
326
// failed = false;
327
// } finally
328
// // failed==true means there was an exception and
329
// // commit won't be called...
330
// if (failed==true) tmp.delete();
331
// }
332
// commit(tmp,basename)
333
//
334
private static File JavaDoc newXmlTmpFile(String JavaDoc basename) throws IOException JavaDoc {
335         final File JavaDoc f = new File JavaDoc(basename+".new");
336         if (!f.createNewFile())
337             throw new IOException JavaDoc("file "+f.getName()+" already exists");
338  
339         try {
340             final OutputStream JavaDoc newStream = new FileOutputStream JavaDoc(f);
341             try {
342                 final String JavaDoc decl =
343                     "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
344                 newStream.write(decl.getBytes("UTF-8"));
345                 newStream.flush();
346             } finally {
347                 newStream.close();
348             }
349         } catch (IOException JavaDoc x) {
350             f.delete();
351             throw x;
352         }
353         return f;
354     }
355     
356     // Commit the temporary file by renaming <basename> to <baesname>~
357
// and tmpFile to <basename>.
358
private static File JavaDoc commit(String JavaDoc basename, File JavaDoc tmpFile)
359         throws IOException JavaDoc {
360         try {
361             final String JavaDoc backupName = basename+"~";
362             final File JavaDoc desired = new File JavaDoc(basename);
363             final File JavaDoc backup = new File JavaDoc(backupName);
364             backup.delete();
365             if (desired.exists()) {
366                 if (!desired.renameTo(new File JavaDoc(backupName)))
367                     throw new IOException JavaDoc("can't rename to "+backupName);
368             }
369             if (!tmpFile.renameTo(new File JavaDoc(basename)))
370                 throw new IOException JavaDoc("can't rename to "+basename);
371         } catch (IOException JavaDoc x) {
372             tmpFile.delete();
373             throw x;
374         }
375         return new File JavaDoc(basename);
376     }
377     
378     /**
379      * Creates a new committed XML file for {@code <basename>}, containing only
380      * the {@code <?xml ...?>} header.
381      * <p>This method will rename {@code <basename>} to {@code <basename>~},
382      * if it exists.
383      * </p>
384      * @return A newly created XML file containing the regular
385      * {@code <?xml ...?>} header.
386      * @param basename The name of the new file.
387      * @throws IOException if the new XML file couldn't be created.
388      */

389     public static File JavaDoc createNewXmlFile(String JavaDoc basename) throws IOException JavaDoc {
390         return commit(basename,newXmlTmpFile(basename));
391     }
392
393 }
394
Popular Tags