KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > system > pm > XMLAttributePersistenceManager


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.system.pm;
23
24 import java.beans.PropertyEditor JavaDoc;
25 import java.beans.PropertyEditorManager JavaDoc;
26 import java.io.ByteArrayInputStream JavaDoc;
27 import java.io.ByteArrayOutputStream JavaDoc;
28 import java.io.File JavaDoc;
29 import java.io.FileInputStream JavaDoc;
30 import java.io.FileOutputStream JavaDoc;
31 import java.io.FilenameFilter JavaDoc;
32 import java.io.IOException JavaDoc;
33 import java.io.InputStream JavaDoc;
34 import java.io.ObjectInputStream JavaDoc;
35 import java.io.ObjectOutputStream JavaDoc;
36 import java.io.OutputStream JavaDoc;
37 import java.io.Serializable JavaDoc;
38 import java.net.URL JavaDoc;
39 import java.text.SimpleDateFormat JavaDoc;
40 import java.util.Collections JavaDoc;
41 import java.util.Date JavaDoc;
42 import java.util.HashMap JavaDoc;
43 import java.util.Map JavaDoc;
44
45 import javax.management.Attribute JavaDoc;
46 import javax.management.AttributeList JavaDoc;
47 import javax.xml.parsers.DocumentBuilder JavaDoc;
48 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
49 import javax.xml.transform.OutputKeys JavaDoc;
50 import javax.xml.transform.Result JavaDoc;
51 import javax.xml.transform.Source JavaDoc;
52 import javax.xml.transform.Transformer JavaDoc;
53 import javax.xml.transform.TransformerFactory JavaDoc;
54 import javax.xml.transform.dom.DOMSource JavaDoc;
55 import javax.xml.transform.stream.StreamResult JavaDoc;
56
57 import org.jboss.logging.Logger;
58 import org.jboss.mx.persistence.AttributePersistenceManager;
59 import org.jboss.system.server.ServerConfigLocator;
60 import org.jboss.util.file.Files;
61 import org.w3c.dom.Comment JavaDoc;
62 import org.w3c.dom.Document JavaDoc;
63 import org.w3c.dom.Element JavaDoc;
64 import org.w3c.dom.Node JavaDoc;
65 import org.w3c.dom.NodeList JavaDoc;
66 import org.w3c.dom.Text JavaDoc;
67
68 /**
69  * XMLAttributePersistenceManager
70  *
71  * @author <a HREF="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
72  * @version $Revision: 57108 $
73 **/

74 public class XMLAttributePersistenceManager
75    implements AttributePersistenceManager
76 {
77    // Constants -----------------------------------------------------
78

79    /** The XML configuration element */
80    public static final String JavaDoc DATA_DIR_ELEMENT = "data-directory";
81    
82    /** Default base directory if one not specified */
83    public static final String JavaDoc DEFAULT_BASE_DIR = "data/xmbean-attrs";
84    
85    /** The XML attribute-list elements and attributes */
86    public static final String JavaDoc AL_ROOT_ELEMENT = "attribute-list";
87    public static final String JavaDoc AL_ID_ATTRIBUTE = "id";
88    public static final String JavaDoc AL_DATE_ATTRIBUTE = "date";
89    public static final String JavaDoc AL_ATTRIBUTE_ELEMENT = "attribute";
90    public static final String JavaDoc AL_NAME_ATTRIBUTE = "name";
91    public static final String JavaDoc AL_TYPE_ATTRIBUTE = "type";
92    public static final String JavaDoc AL_NULL_ATTRIBUTE = "null";
93    public static final String JavaDoc AL_SERIALIZED_ATTRIBUTE = "serialized";
94    public static final String JavaDoc AL_TRUE_VALUE = "true";
95    public static final String JavaDoc AL_FALSE_VALUE = "false";
96     
97    // Private Data --------------------------------------------------
98

99    /** Logger object */
100    private static final Logger log = Logger.getLogger(XMLAttributePersistenceManager.class);
101    
102    /** used for formating timestamps (date attribute) */
103    private static final SimpleDateFormat JavaDoc dateFormat = new SimpleDateFormat JavaDoc("yyyyMMddHHmmss");
104    
105    /** for byte-to-hex conversions */
106    private static final char[] hexDigits = new char[]
107       { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
108
109    /** directory as used internally */
110    private File JavaDoc dataDir;
111    
112    /** enable status */
113    private boolean state;
114    
115    /** id to filename cache */
116    private Map JavaDoc idMap;
117    
118    // Constructors -------------------------------------------------
119

120    /**
121     * Constructs a <tt>FileAttributePersistenceManager</tt>.
122    **/

123    public XMLAttributePersistenceManager()
124    {
125       log.debug("Constructed");
126    }
127    
128    // AttributePersistenceManager Lifecycle -------------------------
129

130    /**
131     * Initializes the AttributePersistenceManager using
132     * the supplied configuration element CONFIG_ELEMENT
133     * whose content will be probably different for each
134     * particular implementation.
135     *
136     * The version string is a tag that must be used by the
137     * AttributePersistenceManager implementation to make
138     * sure that data saved/loaded under different version
139     * tags are partitioned.
140     *
141     * Once created, the configuration of the implementation
142     * object cannot change.
143     *
144     * Calling any other method before create() is executed
145     * will result in a IllegalStateException
146     *
147     * Finally, the implementation should be prepared to
148     * receive multiple concurrent calls.
149     *
150     * @param version a tag to identify the version
151     * @param config XML Element to load arbitrary config
152     * @throws Exception when any error occurs during create
153     */

154    public void create(String JavaDoc version, Element JavaDoc config)
155       throws Exception JavaDoc
156    {
157       // ignore if already active
158
if (getState()) {
159          return;
160       }
161       
162       // Decide on the base data directory to use
163
String JavaDoc baseDir = null;
164       
165       if (config == null) {
166          baseDir = DEFAULT_BASE_DIR;
167       }
168       else {
169          if (!config.getTagName().equals(DATA_DIR_ELEMENT)) {
170             throw new Exception JavaDoc("expected '" + DATA_DIR_ELEMENT +
171                                 "' XML configuration element, got '" +
172                                 config.getTagName() + "'");
173          }
174          else {
175             baseDir = getElementContent(config);
176          }
177       }
178
179       // Initialize the data dir
180
this.dataDir = initDataDir(baseDir, version);
181       
182       log.debug("Using data directory: " + this.dataDir.getCanonicalPath());
183       
184       // initialize id cache
185
this.idMap = Collections.synchronizedMap(new HashMap JavaDoc());
186
187       // mark active status
188
setState(true);
189    }
190
191    /**
192     * Returns true if the AttributePersistenceManager
193     * is "in-service" state, i.e. after create() and
194     * before destroy() has been called, false otherwise.
195     *
196     * @return true if in operational state
197     */

198    public boolean getState()
199    {
200       return this.state;
201    }
202    
203    /**
204     * Releases resources and destroys the AttributePersistenceManager.
205     * The object is unusable after destroy() has been called.
206     *
207     * Any call to any method will result to an
208     * IllegalStateException.
209     *
210     */

211    public void destroy()
212    {
213       setState(false);
214
215       // instance can't be use anymore
216
this.dataDir = null;
217       this.idMap = null;
218    }
219    
220    // AttributePersistenceManager Persistence -----------------------
221

222    /**
223     * Uses the specified id to retrieve a previously persisted
224     * AttributeList. If no data can be found under the specified
225     * id, a null will be returned.
226     *
227     * @param id the key for retrieving the data
228     * @return the data, or null
229     * @throws Exception when an error occurs
230     */

231    public void store(String JavaDoc id, AttributeList JavaDoc attrs)
232       throws Exception JavaDoc
233    {
234       log.debug("store(" + id + ") attrs=" + attrs);
235
236       // make sure we are active
237
checkActiveState();
238       
239       // map to filename - keep the original for storing
240
String JavaDoc origId = id;
241       id = mapId(id);
242       
243       if (attrs == null)
244          throw new Exception JavaDoc("store() called with null AttributeList");
245       
246       // will throw an exception if file not r/w or it is a directory
247
File JavaDoc file = checkFileForWrite(id);
248       
249       // build the XML in memory using DOM
250
DocumentBuilder JavaDoc builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
251       Document JavaDoc doc = builder.newDocument();
252
253       // Add a comment
254
Comment JavaDoc comment = doc.createComment(" automatically produced by XMLAttributePersistenceManager ");
255       doc.appendChild(comment);
256       
257       // Insert root element
258
Element JavaDoc root = doc.createElement(AL_ROOT_ELEMENT);
259       root.setAttribute(AL_ID_ATTRIBUTE, origId);
260       root.setAttribute(AL_DATE_ATTRIBUTE, dateFormat.format(new Date JavaDoc()));
261       doc.appendChild(root);
262       
263       // iterate over the AttributeList
264
for (int i = 0; i < attrs.size(); i++) {
265          
266          Attribute JavaDoc attr = (Attribute JavaDoc)attrs.get(i);
267        
268          String JavaDoc name = attr.getName();
269          Object JavaDoc value = attr.getValue();
270          
271          // create the Element and decide how to fill it in
272
Element JavaDoc element = doc.createElement(AL_ATTRIBUTE_ELEMENT);
273          element.setAttribute(AL_NAME_ATTRIBUTE, name);
274          
275          if (value == null) {
276             // (a) null value - mark it as null
277
element.setAttribute(AL_NULL_ATTRIBUTE, AL_TRUE_VALUE);
278             
279             // append the attribute to the attribute-list
280
root.appendChild(element);
281          }
282          else if (value instanceof org.w3c.dom.Element JavaDoc) {
283             // (b) XML Element - mark the type and append a copy of it
284
element.setAttribute(AL_TYPE_ATTRIBUTE, "org.w3c.dom.Element");
285             
286             Node JavaDoc copy = doc.importNode((org.w3c.dom.Element JavaDoc)value, true);
287             element.appendChild(copy);
288             
289             // append the attribute to the attribute-list
290
root.appendChild(element);
291          }
292          else {
293             Class JavaDoc clazz = value.getClass();
294             String JavaDoc type = clazz.getName();
295             PropertyEditor JavaDoc peditor = PropertyEditorManager.findEditor(clazz);
296
297             if (peditor != null) {
298                // (c) use a PropertyEditor - mark the type and append the value as string
299
peditor.setValue(value);
300                
301                element.setAttribute(AL_TYPE_ATTRIBUTE, type);
302                element.appendChild(doc.createTextNode(peditor.getAsText()));
303                
304                // append the attribute to the attribute-list
305
root.appendChild(element);
306             }
307             else if (value instanceof Serializable JavaDoc) {
308                // (d) serialize the object - mark type and serialized attribute
309
// - encode the value as stringfied sequence of hex
310
String JavaDoc encoded = encodeAsHexString((Serializable JavaDoc)value);
311                
312                if (encoded != null) {
313                   element.setAttribute(AL_TYPE_ATTRIBUTE, type);
314                   element.setAttribute(AL_SERIALIZED_ATTRIBUTE, AL_TRUE_VALUE);
315                   element.appendChild(doc.createTextNode(encoded));
316
317                   // append the attribute to the attribute-list
318
root.appendChild(element);
319                }
320                else {
321                   // could not serialize the object - write and log a warning
322
root.appendChild(doc.createComment(
323                         " WARN <attribute name=\"" + name + "\" type=\"" + type +
324                         "\"/> could not be serialized "));
325                   
326                   log.warn("Could not serialize attribute '" + name +
327                            "' of type '" + type + "' and value: " + value);
328                }
329             }
330             else {
331                // (e) could not find a way to persist - record and log a warning
332
root.appendChild(doc.createComment(
333                      " WARN <attribute name=\"" + name + "\" type=\"" + type +
334                      "\"/> could not be persisted "));
335                
336                log.warn("Could not find a way to persist attribute '" + name +
337                         "' of type '" + type + "' and value: " + value);
338             }
339          }
340       }
341       
342       // DOM document ready - save it
343
try {
344          outputXmlFile(doc, file);
345       }
346       catch (Exception JavaDoc e) {
347          log.warn("Cannot persist AttributeList to: \"" + id + "\"", e);
348          throw e;
349       }
350    }
351    
352    /**
353     * Persists an AttributeList (name/value pair list),
354     * under a specified id. The id can be used to retrieve the
355     * AttributeList later on. The actual mechanism will differ
356     * among implementations.
357     *
358     * @param id the key for retrieving the data later on, not null
359     * @param attrs the data to be persisted, not null
360     * @throws Exception when data cannot be persisted
361     */

362    public AttributeList JavaDoc load(String JavaDoc id)
363       throws Exception JavaDoc
364    {
365       log.debug("load(" + id + ")");
366
367       // make sure we are active
368
checkActiveState();
369       
370       // map to filename
371
id = mapId(id);
372       
373       if (!getState())
374          return null;
375       
376       // Real stuff starts here
377
AttributeList JavaDoc attrs = null;
378       
379       // returns null to indicate file does not exist
380
File JavaDoc file = checkFileForRead(id);
381       
382       if (file != null) {
383          // parse the saved XML doc
384
Document JavaDoc doc = parseXmlFile(file);
385          
386          // top level - look for AL_ROOT_ELEMENT
387
NodeList JavaDoc docList = doc.getChildNodes();
388          Element JavaDoc root = null;
389          
390          for (int i = 0; i < docList.getLength(); i++) {
391             Node JavaDoc node = docList.item(i);
392             
393             if (node.getNodeType() == Node.ELEMENT_NODE &&
394                 node.getNodeName().equals(AL_ROOT_ELEMENT)) {
395                
396                root = (Element JavaDoc)node;
397                break; // found
398
}
399          }
400          
401          // root element must be there
402
if (root == null) {
403             throw new Exception JavaDoc("Expected XML element: " + AL_ROOT_ELEMENT);
404          }
405          else {
406             // proceed iterating over AL_ATTRIBUTE_ELEMENT elements
407
// and fill the AttributeList
408
attrs = new AttributeList JavaDoc();
409             
410             NodeList JavaDoc rootList = root.getChildNodes();
411             
412             for (int i = 0; i < rootList.getLength(); i++) {
413                Node JavaDoc node = rootList.item(i);
414                
415                // only interested in ELEMENT nodes
416
if (node.getNodeType() == Node.ELEMENT_NODE &&
417                    node.getNodeName().equals(AL_ATTRIBUTE_ELEMENT)) {
418                   
419                   Element JavaDoc element = (Element JavaDoc)node;
420                   
421                   // name attribute must always be there
422
String JavaDoc name = element.getAttribute(AL_NAME_ATTRIBUTE);
423                   
424                   if (!(name.length() > 0)) {
425                      throw new Exception JavaDoc("Attribute '" + AL_NAME_ATTRIBUTE +
426                                          "' must be specified for element '" + AL_ATTRIBUTE_ELEMENT + "'");
427                   }
428                   
429                   // Process the attribute depending on how the attributes are set
430

431                   if (element.getAttribute(AL_NULL_ATTRIBUTE).toLowerCase().equals(AL_TRUE_VALUE)) {
432                      
433                      // (a) null value - just add it to the AttributeList
434
attrs.add(new Attribute JavaDoc(name, null));
435                   }
436                   else if (element.getAttribute(AL_SERIALIZED_ATTRIBUTE).toLowerCase().equals(AL_TRUE_VALUE)) {
437                      
438                      // (b) serialized value - decode the HexString
439
String JavaDoc hexStr = getElementContent(element);
440                      Serializable JavaDoc obj = decodeFromHexString(hexStr);
441                      
442                      if (obj == null) {
443                         throw new Exception JavaDoc("Failed to deserialize attribute '" + name + "'");
444                      }
445                      else {
446                         attrs.add(new Attribute JavaDoc(name, obj));
447                      }
448                   }
449                   else {
450                      String JavaDoc type = element.getAttribute(AL_TYPE_ATTRIBUTE);
451                      
452                      // type must be specified
453
if (!(type.length() > 0)) {
454                         throw new Exception JavaDoc("Attribute '" + AL_TYPE_ATTRIBUTE +
455                                             "' must be specified for name='" + name + "'");
456                      }
457                      
458                      if (type.equals("org.w3c.dom.Element")) {
459
460                         // (c) org.w3c.dom.Element - deep copy first Element child node found
461

462                          NodeList JavaDoc nlist = element.getChildNodes();
463                          Element JavaDoc el = null;
464                          
465                          for (int j = 0; j < nlist.getLength(); j++) {
466                             
467                             Node JavaDoc n = nlist.item(j);
468                             if (n.getNodeType() == Node.ELEMENT_NODE)
469                             {
470                                el = (Element JavaDoc)n;
471                                break;
472                             }
473                          }
474                          
475                          if (el != null) {
476                             attrs.add(new Attribute JavaDoc(name, el.cloneNode(true)));
477                          }
478                          else {
479                             attrs.add(new Attribute JavaDoc(name, null));
480                          }
481                      }
482                      else {
483                         // Get the classloader for loading attribute classes.
484
ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
485                         Class JavaDoc clazz = null;
486                         
487                          try {
488                             clazz = cl.loadClass(type);
489                          }
490                          catch (ClassNotFoundException JavaDoc e) {
491                             throw new Exception JavaDoc("Class not found for attribute '" + name +
492                                                 "' of type '" + type + "'");
493                          }
494
495                          PropertyEditor JavaDoc peditor = PropertyEditorManager.findEditor(clazz);
496
497                          if (peditor != null) {
498                             
499                             // (d) use a PropertyEditor - extract the value
500

501                             String JavaDoc value = getElementContent(element);
502                             peditor.setAsText(value);
503                             
504                             attrs.add(new Attribute JavaDoc(name, peditor.getValue()));
505                          }
506                          else {
507                             throw new Exception JavaDoc("Cannot find a way to load attribute '" + name +
508                                                 "' of type '" + type + "'");
509                          }
510                      }
511                   }
512                }
513             } // end for()
514
}
515       }
516       log.debug("load() returns with: " + attrs);
517       
518       // will be null if a persistent file was not found
519
return attrs;
520    }
521
522    // Administrative Functions --------------------------------------
523

524    /**
525     * Checks if a persistened AttributeList for this particular
526     * id exists
527     *
528     * @param id the key of the image
529     * @return true if an image exists; false otherwise
530     * @throws Exception on any error
531     */

532    public boolean exists(String JavaDoc id)
533       throws Exception JavaDoc
534    {
535       // make sure we are active
536
checkActiveState();
537       
538       return (new File JavaDoc(this.dataDir, mapId(id))).isFile();
539    }
540    
541    /**
542     * Removes the persisted AttributeList, if exists
543     *
544     * @param id the key of the image
545     * @throws Exception when any error occurs
546     */

547    public void remove(String JavaDoc id)
548       throws Exception JavaDoc
549    {
550       // make sure we are active
551
checkActiveState();
552       
553       (new File JavaDoc(this.dataDir, mapId(id))).delete();
554    }
555    
556    /**
557     * Removes all the persisted data stored under
558     * the configured version tag.
559     *
560     * @throws Exception when any error occurs
561     */

562    public void removeAll()
563       throws Exception JavaDoc
564    {
565       // make sure we are active
566
checkActiveState();
567       
568       String JavaDoc[] files = this.dataDir.list(new XMLFilter());
569       
570       if (files != null) {
571          for (int i = 0; i < files.length; i++) {
572             (new File JavaDoc(this.dataDir, files[i])).delete();
573          }
574       }
575    }
576    
577    /**
578     * Returns a String array with all the saved ids
579     * under the configured version tag.
580     *
581     * @return array with all persisted ids
582     * @throws Exception when any error occurs
583     */

584    public String JavaDoc[] listAll()
585       throws Exception JavaDoc
586    {
587       // make sure we are active
588
checkActiveState();
589       
590       String JavaDoc[] files = this.dataDir.list(new XMLFilter());
591       String JavaDoc[] result = null;
592       
593       if (files != null) {
594          result = new String JavaDoc[files.length];
595          
596          for (int i = 0; i < files.length; i++) {
597             result[i] = mapFile(files[i]);
598          }
599       }
600       return result;
601    }
602    
603    // Private -------------------------------------------------------
604

605    /**
606     * Private status setter
607     *
608     * lifecycle is controlled by create() and destroy()
609     */

610    private void setState(boolean state)
611    {
612       this.state = state;
613    }
614    
615    /**
616     * Create/check/point to the data directory.
617     *
618     * Process the base dir first and append the versionTag dir
619     * if specified.
620     *
621     * Only a base dir relative to ServerHomeDir is created.
622     * External base dirs are only used (i.e. they must exist
623     * and we must read/write permission)
624     */

625    private File JavaDoc initDataDir(String JavaDoc baseDir, String JavaDoc versionTag)
626       throws Exception JavaDoc
627    {
628       File JavaDoc dir = null;
629       
630       // Process the base directory first
631

632       // baseDir must be valid URL pointing to r/w dir
633
try {
634          URL JavaDoc fileURL = new URL JavaDoc(baseDir);
635           
636          File JavaDoc file = new File JavaDoc(fileURL.getFile());
637           
638          if(file.isDirectory() && file.canRead() && file.canWrite()) {
639             dir = file;
640          }
641       }
642       catch(Exception JavaDoc e) {
643          // Otherwise, try to make it inside the jboss directory hierarchy
644

645          File JavaDoc homeDir = ServerConfigLocator.locate().getServerHomeDir();
646     
647          dir = new File JavaDoc(homeDir, baseDir);
648     
649          dir.mkdirs();
650           
651          if (!dir.isDirectory())
652             throw new Exception JavaDoc("The base directory is not valid: "
653                                 + dir.getCanonicalPath());
654       }
655       
656       // Now add the versionTag dir, if specified
657
if (versionTag != null && !versionTag.equals("")) {
658          dir = new File JavaDoc(dir, versionTag);
659          
660          dir.mkdirs();
661           
662          if (!dir.isDirectory())
663             throw new Exception JavaDoc("The data directory is not valid: "
664                                 + dir.getCanonicalPath());
665       }
666       return dir;
667    }
668    
669    /**
670     * Serialize an object as a Hex string so it can be saved as text
671     *
672     * The length of the encoded object is twice it's byte image
673     *
674     * Returns null if serialization fails
675     */

676    private String JavaDoc encodeAsHexString(Serializable JavaDoc obj)
677    {
678       String JavaDoc retn = null;
679       
680       if (obj != null) {
681          try {
682             ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc(1024);
683             ObjectOutputStream JavaDoc oos = new ObjectOutputStream JavaDoc(baos);
684           
685             oos.writeObject(obj);
686             byte[] bytes = baos.toByteArray();
687             
688             StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc(1024);
689
690             for (int i = 0; i < bytes.length; i++) {
691                 sbuf.append(hexDigits[ (bytes[i] >> 4) & 0xF ]); // high order digit
692
sbuf.append(hexDigits[ (bytes[i] ) & 0xF ]); // low order digit
693
}
694
695             retn = sbuf.toString();
696          }
697          catch (IOException JavaDoc e) {
698             // will return null
699
}
700       }
701       return retn;
702    }
703
704    /**
705     * Deserialize an object from its hex encoded string representation
706     *
707     * Returns null if deserialization fails
708     */

709    private Serializable JavaDoc decodeFromHexString(String JavaDoc hexStr)
710    {
711       // hexStr must not contain white space!
712
int len = hexStr.length() / 2;
713       byte[] bytes = new byte[len];
714       
715       for (int i = 0; i < len; i++) {
716          
717           char h1 = hexStr.charAt(i * 2); // high order hex digit
718
char h2 = hexStr.charAt(i * 2 + 1); // low order hex digit
719

720           // convert hex digits to integers
721
int d1 = (h1 >= 'a') ? (10 + h1 - 'a')
722                 : ((h1 >= 'A') ? (10 + h1 - 'A')
723                                    : (h1 - '0'));
724           
725           int d2 = (h2 >= 'a') ? (10 + h2 - 'a')
726                 : ((h2 >= 'A') ? (10 + h2 - 'A')
727                                     : (h2 - '0'));
728           
729           bytes[i] = (byte)(d1 * 16 + d2); // 255 max
730
}
731       
732       Serializable JavaDoc retn = null;
733       
734       try {
735          ByteArrayInputStream JavaDoc bais = new ByteArrayInputStream JavaDoc(bytes);
736          ObjectInputStream JavaDoc ois = new ObjectInputStream JavaDoc(bais);
737          
738          retn = (Serializable JavaDoc)ois.readObject();
739       }
740       catch (IOException JavaDoc e) {
741          log.warn("Cannot deserialize object", e); }
742       catch (ClassNotFoundException JavaDoc e) {
743          log.warn("Cannot deserialize object", e);
744       }
745       
746       return retn;
747    }
748    
749    /**
750     * Just output a DOM Document to a file with
751     * indentation true
752     */

753    private void outputXmlFile(Document JavaDoc doc, File JavaDoc file)
754       throws Exception JavaDoc
755    {
756       // Prepare the DOM document for writing
757
Source JavaDoc source = new DOMSource JavaDoc(doc);
758       
759       // Use an OutputStream rather than a File
760
OutputStream JavaDoc out = new FileOutputStream JavaDoc(file);
761       
762       // Prepare the output
763
Result JavaDoc result = new StreamResult JavaDoc(out);
764       
765       // Write the DOM document to the file
766
Transformer JavaDoc xformer = TransformerFactory.newInstance().newTransformer();
767       
768       // Enable indentation
769
xformer.setOutputProperty(OutputKeys.INDENT, "yes");
770       
771       try
772       {
773          xformer.transform(source, result);
774       }
775       finally
776       {
777          // Cleanup
778
out.close();
779       }
780    }
781
782    /**
783     * Parse an XML file into a DOM Document
784     * with validation set to false
785     */

786    private Document JavaDoc parseXmlFile(File JavaDoc file)
787       throws Exception JavaDoc
788    {
789        // Create a builder factory
790
DocumentBuilderFactory JavaDoc factory = DocumentBuilderFactory.newInstance();
791        
792        // do not request validation against DTD
793
// no DTD specified in the saved document
794
factory.setValidating(false);
795
796       // The builder and document to return
797
DocumentBuilder JavaDoc builder = factory.newDocumentBuilder();
798       Document JavaDoc doc;
799       
800       // Use an InputStreamer rather than a File when parsing,
801
// to avoid pathname encoding problems, like spaces in
802
// the pathname encoded as %20
803
InputStream JavaDoc in = new FileInputStream JavaDoc(file);
804       try
805       {
806          // Parse the file
807
doc = builder.parse(in);
808       }
809       finally
810       {
811          // close anyways
812
in.close();
813       }
814       // Return the parsed document
815
return doc;
816    }
817    
818    /**
819     * Makes sure we can write to this file
820     */

821    private File JavaDoc checkFileForWrite(String JavaDoc filename)
822       throws Exception JavaDoc
823    {
824       File JavaDoc file = new File JavaDoc(this.dataDir, filename);
825       
826       if (file.isFile()) {
827          if (file.canRead() && file.canWrite()) {
828             return file; // everything fine
829
}
830          else {
831             throw new Exception JavaDoc("file '" + filename + "' is not r/w"); // oops
832
}
833       }
834       else if (file.isDirectory()) {
835          throw new Exception JavaDoc(filename + " is a directory!"); // oops
836
}
837       else {
838          return file; // not found - ok
839
}
840    }
841    
842    /**
843     * Makes sure we can read from this file.
844     *
845     * Returns null if not found
846     */

847    private File JavaDoc checkFileForRead(String JavaDoc filename)
848       throws Exception JavaDoc
849    {
850       File JavaDoc file = new File JavaDoc(this.dataDir, filename);
851       
852       if (file.isFile()) {
853          if (file.canRead() && file.canWrite()) {
854             return file; // everything fine
855
}
856          else {
857             throw new Exception JavaDoc("file '" + filename + "' is not r/w"); // oops
858
}
859       }
860       else if (file.isDirectory()) {
861          throw new Exception JavaDoc(filename + " is a directory!"); // oops
862
}
863       else {
864          return null; // not found
865
}
866    }
867    
868    /**
869     * Returns the concatenated content of all
870     * children TEXT nodes of this element
871     */

872    private String JavaDoc getElementContent(Element JavaDoc element)
873    {
874       NodeList JavaDoc nlist = element.getChildNodes();
875       
876       StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc(1024);
877    
878       // concatenate Text nodes
879
for (int i = 0; i < nlist.getLength(); i++) {
880          Node JavaDoc node = nlist.item(i);
881          
882          if (node.getNodeType() == Node.TEXT_NODE) {
883             sbuf.append(((Text JavaDoc)node).getData());
884          }
885       }
886       return sbuf.toString();
887    }
888    
889    /**
890     * Make sure we are active before processing a call
891     */

892    private void checkActiveState()
893    {
894       if (!getState()) {
895          throw new IllegalStateException JavaDoc("AttributePersistenceManager not active");
896       }
897    }
898    
899    /**
900     * Simple filter for .xml files in a directory listing
901     */

902    private class XMLFilter
903       implements FilenameFilter JavaDoc
904    {
905       public boolean accept(File JavaDoc dir, String JavaDoc name)
906       {
907          return name.endsWith(".xml");
908       }
909    }
910    
911    /**
912     * Map the id to a filename and cache it
913     *
914     * A null id results in an exception thrown
915     */

916    private String JavaDoc mapId(String JavaDoc id)
917       throws Exception JavaDoc
918    {
919       if (id == null) {
920          throw new Exception JavaDoc("called with null id");
921       }
922       else {
923          // check the cache
924
String JavaDoc file = (String JavaDoc)this.idMap.get(id);
925          
926          // if not in cache encode, and cache it
927
if (file == null) {
928             file = Files.encodeFileName(id) + ".xml";
929             this.idMap.put(id, file);
930          }
931          return file;
932       }
933    }
934    
935    /**
936     * Do the reverse mapping file to id
937     */

938    private String JavaDoc mapFile(String JavaDoc file)
939    {
940       if (file == null) {
941          return null;
942       }
943       else {
944          // remove .xml suffix
945
file = file.substring(0, file.length() - 4);
946          
947          return Files.decodeFileName(file);
948       }
949    }
950 }
951
Popular Tags