Java tutorial
/** * @(#)XMLFileConfigDocument.java, 2013-2-24. * * Copyright 2013 Netease, Inc. All rights reserved. * NETEASE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package com.git.original.common.config; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayDeque; import java.util.Deque; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * XML? * <p> * ?: XML????Element, ??Attribute * * * @author linaoxiang */ public class XMLFileConfigDocument extends BaseConfigDocument { /** */ private static final Logger LOG = LoggerFactory.getLogger(XMLFileConfigDocument.class); /** * ? */ protected String configFilePath = null; /** * ??? * <p> * ?????? */ private String configFileDigest = StringUtils.EMPTY; /** * ??? */ private String dbVersion = null; /** * ???(?, ???) */ private boolean ignoreDb = false; /** * ??????,?() */ private Long scanMillis = null; /** * * * @param confPath * ??, ?HMAIL_HOME */ public XMLFileConfigDocument(String confPath) { super(); this.configFilePath = confPath; } /** * ? * * @param rootNode * ? */ XMLFileConfigDocument(ConfigNode rootNode) { super(rootNode); } @Override protected ConfigNode doLoad() throws Exception { return doLoad(this.configFilePath); } protected ConfigNode doLoad(String configFilePath) throws Exception { InputStream in = null; try { File confFile = new File(configFilePath); if (!confFile.isAbsolute()) { confFile = new File(this.getHmailHome(), configFilePath); } if (!confFile.exists()) { throw new FileNotFoundException("path:" + confFile); } String currentDigest = confFile.lastModified() + ";" + confFile.length(); if (currentDigest.equals(this.configFileDigest)) { // ??, ? return null; } in = new FileInputStream(confFile); SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); NodeBuilder nb = new NodeBuilder(); parser.parse(in, nb); ConfigNode result = nb.getRootNode(); if (result != null) { try { this.dbVersion = result.getAttribute(CONF_DOC_ATTRIBUTE_DB_VERSION); } catch (Exception ex) { this.dbVersion = null; } try { String str = result.getAttribute(CONF_DOC_ATTRIBUTE_IGNORE_DB); if (StringUtils.isEmpty(str)) { this.ignoreDb = false; } else { this.ignoreDb = Boolean.parseBoolean(str); } } catch (Exception ex) { this.ignoreDb = false; } try { String tmp = result.getAttribute(CONF_DOC_ATTRIBUTE_SCAN_PERIOD); if (StringUtils.isEmpty(tmp)) { this.scanMillis = null; } else { this.scanMillis = ConfigNode.textToNumericMillis(tmp.trim()); } } catch (Exception ex) { this.scanMillis = null; } } LOG.debug("Load config from local dir success, file:{}", configFilePath); return result; } finally { if (in != null) { try { in.close(); } catch (IOException e) { // ignore exception } } } } @Override public String toString() { return "[FileConfig]" + configFilePath; } /** * XML?? * * @param elem * XML * @return ? */ static ConfigNode convertElement(Element elem) { if (elem == null) { return null; } ConfigNode cn = new ConfigNode(elem.getTagName(), null); NamedNodeMap attrNodeMap = elem.getAttributes(); if (attrNodeMap != null) { for (int i = 0; i < attrNodeMap.getLength(); i++) { Node node = attrNodeMap.item(i); cn.addAttribute(node.getNodeName(), node.getNodeValue()); } } NodeList nodeList = elem.getChildNodes(); if (nodeList != null && nodeList.getLength() > 0) { for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); switch (node.getNodeType()) { case Node.ATTRIBUTE_NODE: cn.addAttribute(node.getNodeName(), node.getNodeValue()); break; case Node.ELEMENT_NODE: ConfigNode child = convertElement((Element) node); cn.addChild(child); break; case Node.TEXT_NODE: cn.value = node.getNodeValue(); break; default: continue; } } } return cn; } /** * ??XML * * @param cn * ? * @return XML */ @SuppressWarnings("unchecked") static Element convertConfigNode(Document doc, ConfigNode cn) { Element elem = doc.createElement(cn.getName()); Map<String, String> attrMap = cn.attributes(); if (attrMap != null) { for (Entry<String, String> entry : attrMap.entrySet()) { elem.setAttribute(entry.getKey(), entry.getValue()); } } if (cn.hasChildren()) { for (Object child : cn.getAllChildren()) { if (child instanceof List) { List<ConfigNode> cnList = (List<ConfigNode>) child; for (ConfigNode node : cnList) { elem.appendChild(convertConfigNode(doc, node)); } } else { elem.appendChild(convertConfigNode(doc, (ConfigNode) child)); } } } else if (cn.value != null) { elem.setTextContent(cn.value.toString()); } return elem; } @Override public String getDbVersion() { return this.dbVersion; } @Override public boolean ignoreDb() { return this.ignoreDb; } @Override public Long getScanMillis() { return this.scanMillis; } /** {@link ConfigNode} */ private static class NodeBuilder extends DefaultHandler { /** node */ private ConfigNode rootNode = null; /** ?node */ private ConfigNode currentNode = null; /** node(?) */ private Deque<ConfigNode> cnDeque = new ArrayDeque<ConfigNode>(); /** ? */ private StringBuilder tmpValue = new StringBuilder(); /** * @return the rootNode */ public ConfigNode getRootNode() { return rootNode; } /* * (non-Javadoc) * * @see org.xml.sax.helpers.DefaultHandler#startDocument() */ @Override public void startDocument() throws SAXException { cnDeque.clear(); } /* * (non-Javadoc) * * @see org.xml.sax.helpers.DefaultHandler#endDocument() */ @Override public void endDocument() throws SAXException { if (!cnDeque.isEmpty()) { throw new SAXException("cnDeque is not empty"); } } /* * (non-Javadoc) * * @see * org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, * java.lang.String, java.lang.String, org.xml.sax.Attributes) */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { this.currentNode = new ConfigNode(qName, null); if (attributes != null && attributes.getLength() > 0) { for (int i = 0; i < attributes.getLength(); i++) { currentNode.addAttribute(attributes.getQName(i), attributes.getValue(i)); } } this.cnDeque.push(currentNode); this.tmpValue.setLength(0); } /* * (non-Javadoc) * * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, * java.lang.String, java.lang.String) */ @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (this.currentNode != this.cnDeque.pop()) { // ?currentNode? throw new SAXException("current node is not the first one of the cnDeque."); } if (tmpValue.length() > 0) { this.currentNode.value = tmpValue.toString(); } if (!this.cnDeque.isEmpty()) { this.cnDeque.peek().addChild(currentNode); } else { this.rootNode = this.currentNode; } this.currentNode = this.cnDeque.peek(); } /* * (non-Javadoc) * * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int) */ @Override public void characters(char[] ch, int start, int length) throws SAXException { if (!this.cnDeque.isEmpty()) { tmpValue.append(ch, start, length); } } } }