package com.sandwich.koan.path.xmltransformation;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.sandwich.koan.path.PathToEnlightenment.Path;
public class XmlToPathTransformerImpl implements XmlToPathTransformer {
private final File xmlFile;
private final String suiteName;
private final String methodName;
public XmlToPathTransformerImpl(){
xmlFile = null;
suiteName = null;
methodName = null;
}
public XmlToPathTransformerImpl(String xmlFileLocation, String suiteName, String methodName) throws FileNotFoundException {
this.xmlFile = new File(xmlFileLocation);
this.suiteName = suiteName;
this.methodName = methodName;
if(!xmlFile.exists()){
throw new FileNotFoundException(xmlFile.getAbsolutePath()
+ " was not found. it may have been deleted, renamed.");
}
}
public Path transform(){
try{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(xmlFile);
doc.getDocumentElement().normalize();
NodeList nodeLst = doc.getElementsByTagName("package");
/*
* Map of string values read from xml in following form
* package
* |-suite class name
* |-method name
* |-method attributes from xml
*/
Map<String, Map<String, Map<String, KoanElementAttributes>>> koans =
new LinkedHashMap<String, Map<String, Map<String, KoanElementAttributes>>>();
for(int i = 0; i < nodeLst.getLength(); i++){
Node node = nodeLst.item(i);
String packageTitle = node.getAttributes().getNamedItem("name").getNodeValue();
String pkg = node.getAttributes().getNamedItem("pkg").getNodeValue();
koans.put(packageTitle, getKoanElementAttributesByMethodNameBySuite(pkg, node.getChildNodes()));
}
return new Path(methodName, koans);
}catch(Exception x){
throw new RuntimeException(x);
}
}
Map<String, Map<String, KoanElementAttributes>> getKoanElementAttributesByMethodNameBySuite(String pkg,
NodeList childNodes) throws DOMException, ClassNotFoundException,
InstantiationException, IllegalAccessException {
Map<String, Map<String, KoanElementAttributes>> koansByMethodNameByClass =
new LinkedHashMap<String, Map<String, KoanElementAttributes>>();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if ("suite".equalsIgnoreCase(node.getNodeName())) {
String className = pkg + '.' + node.getAttributes().getNamedItem("class").getNodeValue();
if (suiteName == null || suiteName.equalsIgnoreCase(className)) {
koansByMethodNameByClass.put(className, extractKoansAndRawLessons(className, node.getChildNodes()));
}
}
}
return koansByMethodNameByClass;
}
Map<String, KoanElementAttributes> extractKoansAndRawLessons(
String className, NodeList nodes) {
Map<String, KoanElementAttributes> rawKoanAttributesByMethodName = new LinkedHashMap<String, KoanElementAttributes>();
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if ("koan".equalsIgnoreCase(node.getNodeName())) {
NamedNodeMap attributes = node.getAttributes();
String name = attributes.getNamedItem("name").getNodeValue();
Node displayKoanIncompleteExceptionNode = attributes
.getNamedItem("displayIncompleteKoanException");
String displayIncompleteKoanException = displayKoanIncompleteExceptionNode == null ? null
: displayKoanIncompleteExceptionNode.getNodeValue();
if (rawKoanAttributesByMethodName.containsKey(name)) {
throw new DuplicateKoanException(className, name);
}
rawKoanAttributesByMethodName.put(name, new KoanElementAttributes(
name, displayIncompleteKoanException, className));
}
}
return rawKoanAttributesByMethodName;
}
static class DuplicateKoanException extends RuntimeException {
private static final long serialVersionUID = 3846796580641690961L;
public DuplicateKoanException(String className, String name){
super("Duplicate koans in the same suite: "+className+" with the name "+name);
}
}
}