PageRenderTime 43ms CodeModel.GetById 11ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 0ms

/razpub/src/com/razie/pub/base/data/XmlDoc.java

http://razpub.googlecode.com/
Java | 245 lines | 135 code | 26 blank | 84 comment | 18 complexity | 7e5f3266899294c3710599da3ca8a72b MD5 | raw file
  1/**
  2 * Razvan's public code. Copyright 2008 based on Apache license (share alike) see LICENSE.txt for
  3 * details.
  4 * 
  5 * Note that this is based on work I did elsewhere:
  6 * 
  7 * Copyright 2006 - 2007 The Members of the OSS through Java(TM) Initiative. All rights reserved.
  8 * Use is subject to license terms.
  9 */
 10package com.razie.pub.base.data;
 11
 12import java.io.File;
 13import java.io.StringBufferInputStream;
 14import java.net.URL;
 15import java.util.ArrayList;
 16import java.util.HashMap;
 17import java.util.List;
 18import java.util.Map;
 19
 20import org.w3c.dom.Document;
 21import org.w3c.dom.Element;
 22import org.w3c.dom.Node;
 23import org.w3c.dom.NodeList;
 24
 25import com.razie.pub.FileUtils;
 26import com.razie.pub.base.log.Log;
 27
 28/**
 29 * represents an xml document - generally for configuration. For dynamic data, use the XmlDb class.
 30 * 
 31 * <p>
 32 * This is the central point for xml access, usually with xpath.
 33 * 
 34 * <p>
 35 * Registry: when decoupling loading xml docs from their actual use in code
 36 * 
 37 * TODO this class is quite dedicated - I should document in more detail how I see xml docs...
 38 * 
 39 * @author razvanc
 40 */
 41public class XmlDoc {
 42    protected Document            document;
 43    public URL                    myUrl;
 44    protected String              name;
 45    protected Element             root;
 46    protected Map<String, String> prefixes         = null;    // lazy
 47    public long                   fileLastModified = -1;
 48    private long                  lastChecked      = 0;
 49    // TODO use a reasonable interval, make configurable - maybe per db
 50    public long                   reloadMilis      = 1000 * 3;
 51
 52    /** the root element - i'm getting bored typing */
 53    public Element e() {
 54        return root;
 55    }
 56
 57    /**
 58     * add prefix to be used in resolving xpath in this doc...if you use multiple schemas, pay
 59     * attention to this
 60     */
 61    public void addPrefix(String s, String d) {
 62        if (prefixes == null)
 63            prefixes = new HashMap<String, String>();
 64        prefixes.put(s, d);
 65    }
 66
 67    protected void checkFile() {
 68        if (this.reloadMilis > 0 && System.currentTimeMillis() - this.lastChecked >= this.reloadMilis) {
 69            File f = FileUtils.fileFromUrl(this.myUrl);
 70            long ft = f != null ? f.lastModified() : -1;
 71            if (ft != this.fileLastModified) {
 72                Log.logThis ("RELOAD_UPDATED_XMLDB name="+name);
 73                load(name, myUrl);
 74            }
 75        }
 76    }
 77
 78    public XmlDoc load(String name, URL url) {
 79        Log.logThis("XmlDoc:loading from URL=" + url);
 80        this.myUrl = url;
 81        this.name = name;
 82        this.document = RiXmlUtils.readXml(url);
 83        this.root = this.document.getDocumentElement();
 84        if (this.root != null && this.root.hasAttribute("razieReloadMillis")) {
 85            this.reloadMilis = Long.parseLong(this.root.getAttribute("razieReloadMillis"));
 86        }
 87
 88        try {
 89            File f = FileUtils.fileFromUrl(url);
 90            fileLastModified = f != null ? f.lastModified() : -1;
 91            this.lastChecked = System.currentTimeMillis();
 92        } catch (Exception e) {
 93            Log.logThis("XMLDOC won't be refreshed automatically: Can't get datetime for file URL=" + url);
 94            this.reloadMilis = 0;
 95        }
 96
 97        return this;
 98    }
 99
100    protected XmlDoc load(String name, Document d) {
101        this.name = name;
102        this.document = d;
103        this.root = d.getDocumentElement();
104        return this;
105    }
106
107    /**
108     * return a list of all elements in specified path, just their "name" attribute
109     * 
110     * @return never null
111     */
112    public List<String> list(String path) {
113        List<String> ret = new ArrayList<String>();
114        for (Element e : RiXmlUtils.getNodeList(root, path, null)) {
115            ret.add(e.getAttribute("name"));
116        }
117        return ret;
118    }
119
120    /**
121     * return a list of all elements in specified path
122     * 
123     * @return never null
124     */
125    public List<Element> listEntities(String path) {
126        return RiXmlUtils.getNodeList(root, path, prefixes);
127    }
128
129    /**
130     * return a list of all elements in specified path
131     * 
132     * @return never null
133     */
134    public static List<Element> listEntities(Element node, String path) {
135        return RiXmlUtils.getNodeList(node, path, null);
136    }
137
138    /**
139     * return a list of all elements in specified path
140     * 
141     * @return never null
142     */
143    public static List<Element> listEntities(Element node) {
144        List<Element> list = new ArrayList<Element>();
145        NodeList children = node.getChildNodes();
146        for (int i = 0; i < children.getLength(); i++) {
147            Node n = children.item(i);
148            if (n instanceof Element) {
149                list.add((Element) n);
150            }
151        }
152        return list;
153    }
154
155    /**
156     * get a specific element, by "name"
157     * 
158     * @param path identifies the xpath
159     * @name identifies the name attribute of the element - could also be part of xpath instead
160     * @return never null
161     */
162    public static Element getEntity(Element e, String path) {
163        return (Element) RiXmlUtils.getNode(e, path, null);
164    }
165
166    /**
167     * i.e. "/config/mutant/@someattribute"
168     * 
169     * @param path identifies the xpath
170     * @name identifies the name attribute of the element - could also be part of xpath instead
171     * @return never null
172     */
173    public static String getAttr(Element e, String path) {
174        return RiXmlUtils.getStringValue(e, path, null);
175    }
176
177    /**
178     * get a specific element, by "name"
179     * 
180     * @param path identifies the xpath
181     * @name identifies the name attribute of the element - could also be part of xpath instead
182     * @return never null
183     */
184    public Element getEntity(String path) {
185        return (Element) RiXmlUtils.getNode(root, path, prefixes);
186    }
187
188    /**
189     * i.e. "/config/mutant/@someattribute"
190     * 
191     * @param path identifies the xpath
192     * @name identifies the name attribute of the element - could also be part of xpath instead
193     * @return never null
194     */
195    public String getAttr(String path) {
196        return RiXmlUtils.getStringValue(root, path, null);
197    }
198
199    public Document getDocument() {
200        return this.document;
201    }
202
203    public static XmlDoc createFromString(String name, String str) {
204        XmlDoc doc = new XmlDoc();
205        Document d = RiXmlUtils.readXml(new StringBufferInputStream(str), "");
206        doc.load(name, d);
207        return doc;
208    }
209
210    /** see the registry - register factories that load specific documents */
211    public static interface IXmlDocFactory {
212        public XmlDoc make();
213    }
214
215    /**
216     * registry for all static (config) xml documents. You can register a document after loading or
217     * a factory responsible for loading a document
218     */
219    public static class Reg {
220        private static Map<String, IXmlDocFactory> factories = new HashMap<String, IXmlDocFactory>();
221        protected static Map<String, XmlDoc>       allDocs   = new HashMap<String, XmlDoc>();
222
223        /** TEMP */
224        public static void docAdd(String s, XmlDoc d) {
225            allDocs.put(s, d);
226        }
227
228        /** register a factory - this will load the document with the specified name when needed */
229        public static void registerFactory(String s, XmlDoc.IXmlDocFactory factory) {
230            factories.put(s, factory);
231        }
232
233        /** TEMP */
234        public static XmlDoc doc(String s) {
235            XmlDoc d = allDocs.get(s);
236            if (d != null)
237                d.checkFile();
238            else if (factories.containsKey(s)) {
239                d = factories.get(s).make();
240                docAdd(s, d);
241            }
242            return allDocs.get(s);
243        }
244    }
245}