/**
* The contents of this file are subject to the OpenMRS Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC. All Rights Reserved.
*/
package org.openmrs.module;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Vector;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* This class will parse an xml sql diff file
*
* @version 1.0
*/
public class SqlDiffFileParser {
private static Log log = LogFactory.getLog(SqlDiffFileParser.class);
/**
* Get the diff map. Return a sorted map<version, sql statements>
*
* @return SortedMap<String, String>
* @throws ModuleException
*/
public static SortedMap<String, String> getSqlDiffs(Module module) throws ModuleException {
if (module == null)
throw new ModuleException("Module cannot be null");
SortedMap<String, String> map = new TreeMap<String, String>();
InputStream diffStream = null;
// get the diff stream
JarFile jarfile = null;
try {
try {
jarfile = new JarFile(module.getFile());
}
catch (IOException e) {
throw new ModuleException("Unable to get jar file", module.getName(), e);
}
ZipEntry diffEntry = jarfile.getEntry("sqldiff.xml");
if (diffEntry == null) {
log.debug("No sqldiff.xml found for module: " + module.getName());
return map;
} else {
try {
diffStream = jarfile.getInputStream(diffEntry);
}
catch (IOException e) {
throw new ModuleException("Unable to get sql diff file stream", module.getName(), e);
}
}
try {
// turn the diff stream into an xml document
Document diffDoc = null;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
db.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
// When asked to resolve external entities (such as a DTD) we return an InputSource
// with no data at the end, causing the parser to ignore the DTD.
return new InputSource(new StringReader(""));
}
});
diffDoc = db.parse(diffStream);
}
catch (Exception e) {
throw new ModuleException("Error parsing diff sqldiff.xml file", module.getName(), e);
}
Element rootNode = diffDoc.getDocumentElement();
String diffVersion = rootNode.getAttribute("version");
if (!validConfigVersions().contains(diffVersion))
throw new ModuleException("Invalid config version: " + diffVersion, module.getModuleId());
NodeList diffNodes = getDiffNodes(rootNode, diffVersion);
if (diffNodes != null && diffNodes.getLength() > 0) {
int i = 0;
while (i < diffNodes.getLength()) {
Element el = (Element) diffNodes.item(i++);
String version = getElement(el, diffVersion, "version");
String sql = getElement(el, diffVersion, "sql");
map.put(version, sql);
}
}
}
catch (ModuleException e) {
if (diffStream != null) {
try {
diffStream.close();
}
catch (IOException io) {
log.error("Error while closing config stream for module: " + module.getModuleId(), io);
}
}
// rethrow the moduleException
throw e;
}
}
finally {
try {
if (jarfile != null)
jarfile.close();
}
catch (IOException e) {
log.warn("Unable to close jarfile: " + jarfile.getName());
}
}
return map;
}
/**
* Generic method to get a module tag
*
* @param element
* @param version
* @param tag
* @return
*/
private static String getElement(Element element, String version, String tag) {
if (element.getElementsByTagName(tag).getLength() > 0)
return element.getElementsByTagName(tag).item(0).getTextContent();
return "";
}
/**
* List of the valid sqldiff versions
*
* @return
*/
private static List<String> validConfigVersions() {
List<String> versions = new Vector<String>();
versions.add("1.0");
return versions;
}
/**
* Finds the nodes that contain diff information
*
* @param element
* @param version
* @return
*/
private static NodeList getDiffNodes(Element element, String version) {
NodeList diffNodes = null;
if ("1.0".equals(version))
diffNodes = element.getElementsByTagName("diff");
return diffNodes;
}
}