package il.co.topq.refactor.model;
import il.co.topq.refactor.exception.ExtractScenarioTestsException;
import il.co.topq.refactor.exception.ExtractTestUUIDException;
import il.co.topq.refactor.exception.ScenarioXmlParseException;
import il.co.topq.refactor.exception.UnmodifiableFileException;
import il.co.topq.refactor.utils.XmlUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Level;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import jsystem.extensions.sourcecontrol.SourceControlI;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* @author Itai Agmon
* <p/>
* represents an XMLProjectFile
*/
public class ScenarioXMLFile extends JSystemFile {
private final static String XPATH_GET_ALL_SCENARIOS = "//jsystem-ant[contains(@antfile,'${scenarios.base}')]";
private final static String XPATH_GET_ALL_TESTS = "//test";
private final static String XPATH_GET_TEST_NODES = "//test[@name='%s']";
private final static String XPATH_GET_SCENARIO_NODES = "//jsystem-ant[@antfile='${scenarios.base}/%s.xml']";
private final static String XPATH_GET_SCENARIO_ROOT_ELEMENT = "//project";
private final static String XPATH_GET_TEST_UUIDS = "//test[@name='%s']/../sysproperty[@key='jsystem.uuid']/@value";
private Document doc;
// For example: D:\workspaceJSystem\Sandbox\tests\
private final String scenariosFolder;
public ScenarioXMLFile(File xmlFile) {
super(xmlFile);
scenariosFolder = xmlFile.getAbsolutePath().split("scenarios")[0].replaceAll("/", File.separator);
File scenarioFolderFile = new File(scenariosFolder);
if (!scenarioFolderFile.exists() && !scenarioFolderFile.isDirectory()) {
throw new IllegalStateException("Folder " + scenariosFolder + " is illegal");
}
}
private void init() throws ParserConfigurationException, IOException, SAXException {
if (doc != null) {
return;
}
doc = XmlUtils.parseDocument(file);
}
/**
*
* @return the scenario name as specified in the scneario XML file.
* @throws ScenarioXmlParseException
*/
public String getScenarioName() throws ScenarioXmlParseException {
try {
init();
return XmlUtils.getElement(doc, XPATH_GET_SCENARIO_ROOT_ELEMENT).getAttribute("name");
} catch (Exception e) {
log.info("Failed to get scenario name");
throw new ScenarioXmlParseException();
}
}
/**
* Changes the scenario name to the new given name. The change is of the
* name file and in the file xml body.
*
* @param newScenarioName
* @throws ScenarioXmlParseException
* @throws UnmodifiableFileException
* If has problem to access the file.
* @throws IOException
*/
public void rename(final String newScenarioName) throws ScenarioXmlParseException, UnmodifiableFileException,
IOException {
log.info("Renaming scenario " + getScenarioName() + " to " + newScenarioName);
final File newXmlFile = prepareDestinationFile(newScenarioName);
try {
init();
if (!file.renameTo(newXmlFile)) {
throw new UnmodifiableFileException(file);
}
file = newXmlFile;
XmlUtils.getElement(doc, XPATH_GET_SCENARIO_ROOT_ELEMENT).setAttribute("name", newScenarioName);
} catch (Exception e) {
log.log(Level.SEVERE, "Excpetion was caught during renaming of file", e);
throw new ScenarioXmlParseException();
}
}
/**
* Checks that the destination file is good.
*
* @param newScenarioName
* @return detinatio file.
* @throws IOException
*/
private File prepareDestinationFile(String newScenarioName) throws IOException {
final File newXmlFile = new File(scenariosFolder + newScenarioName + ".xml");
if (!newXmlFile.getParentFile().exists()) {
throw new IOException("Scenario destination folder " + newXmlFile.getParentFile().getAbsolutePath()
+ " is not exist");
}
if (newXmlFile.exists()) {
throw new IOException("Scenario XML file with the same name is already exists: "
+ newXmlFile.getAbsolutePath());
}
return newXmlFile;
}
public void rename(final String newScenarioName, SourceControlI sourceControlHandler)
throws ScenarioXmlParseException, UnmodifiableFileException, IOException {
if (null == sourceControlHandler) {
rename(newScenarioName);
return;
}
log.info("Renaming scenario " + getScenarioName() + " to " + newScenarioName);
final File newXmlFile = prepareDestinationFile(newScenarioName);
try {
init();
sourceControlHandler.moveFile(file, newXmlFile);
file = newXmlFile;
XmlUtils.getElement(doc, XPATH_GET_SCENARIO_ROOT_ELEMENT).setAttribute("name", newScenarioName);
} catch (IOException e) {
throw e;
} catch (Exception e) {
log.log(Level.SEVERE, "Excpetion was caught during renaming of file", e);
throw new ScenarioXmlParseException();
}
}
/**
* Check if the test exists in the scenario.
*
* @param testQualifiedName
* @return true if, and only if, the specified test exists in the scenario
* @throws ExtractScenarioTestsException
*/
public boolean isTestExists(CharSequence testQualifiedName) throws ExtractScenarioTestsException {
Set<MethodTest> scenarioTestSet = getScenarioTests();
for (MethodTest test : scenarioTestSet) {
if (test.equals(new MethodTest((String) testQualifiedName, ""))) {
return true;
}
}
return false;
}
public boolean isSubScenarioExists(CharSequence scenarioSourceNamePath) throws ExtractScenarioTestsException {
Set<AntScenario> scenariosSet = getSubScenarios();
for (AntScenario scenario : scenariosSet) {
if (scenario.equals(new AntScenario((String) scenarioSourceNamePath + ".xml"))) {
return true;
}
}
return false;
}
/**
* return a list of all UUIDs that exists for a specific test
*
* @param testQualifiedName
* -
* @return - A list of all test uuid
* @throws il.co.topq.refactor.exception.ExtractTestUUIDException
* - throw in case a UUID cannot be extracted
*/
public List<UUID> getTestUUIDs(CharSequence testQualifiedName) throws ExtractTestUUIDException {
try {
init();
List<UUID> uuidList = new ArrayList<UUID>();
NodeList testUUIDs = XmlUtils.getNodeList(doc, String.format(XPATH_GET_TEST_UUIDS, testQualifiedName));
for (int i = 0; i < testUUIDs.getLength(); i++) {
uuidList.add(UUID.fromString(testUUIDs.item(i).getTextContent()));
}
return uuidList;
} catch (Throwable t) {
throw new ExtractTestUUIDException("Cannot extract the uuid for the test " + testQualifiedName, t);
}
}
public void save() throws TransformerException {
// save the results
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
doc.setXmlStandalone(true);
Result result = new StreamResult(file);
Source source = new DOMSource(doc);
transformer.transform(source, result);
}
public void renameTest(final String testSourceNamePath, final String testTargetNamePath) {
try {
init();
NodeList testNodes = XmlUtils.getNodeList(doc, String.format(XPATH_GET_TEST_NODES, testSourceNamePath));
for (int i = 0; i < testNodes.getLength(); i++) {
((Element) testNodes.item(i)).setAttribute("name", testTargetNamePath);
}
} catch (Throwable t) {
// throw new
// ExtractTestUUIDException("Cannot extract the uuid for the test "
// + testQualifiedName,t);
}
}
public void renameSubScenario(String scenarioSourceNamePath, String scenarioTargetNamePath) {
try {
init();
NodeList scenariosNodes = XmlUtils.getNodeList(doc,
String.format(XPATH_GET_SCENARIO_NODES, scenarioSourceNamePath));
for (int i = 0; i < scenariosNodes.getLength(); i++) {
((Element) scenariosNodes.item(i)).setAttribute("antfile", "${scenarios.base}/"
+ scenarioTargetNamePath + ".xml");
}
} catch (Exception e) {
// TODO: handle exception
}
}
/**
* Retrieve all tests in a specific scenario
*
* @return return a set of MethodTest
* @throws il.co.topq.refactor.exception.ExtractScenarioTestsException
* -
*/
public Set<AntScenario> getSubScenarios() throws ExtractScenarioTestsException {
try {
init();
NodeList scenariosNodes = XmlUtils.getNodeList(doc, XPATH_GET_ALL_SCENARIOS);
Set<AntScenario> scenarios = new HashSet<AntScenario>();
for (int i = 0; i < scenariosNodes.getLength(); i++) {
scenarios.add(new AntScenario(((Element) scenariosNodes.item(i)).getAttribute("antfile").replace(
"${scenarios.base}/", "")));
}
return scenarios;
} catch (Throwable t) {
throw new ExtractScenarioTestsException();
}
}
/**
* Retrieve all tests in a specific scenario
*
* @return return a set of MethodTest
* @throws il.co.topq.refactor.exception.ExtractScenarioTestsException
* -
*/
public Set<MethodTest> getScenarioTests() throws ExtractScenarioTestsException {
try {
init();
NodeList testNodes = XmlUtils.getNodeList(doc, XPATH_GET_ALL_TESTS);
Set<MethodTest> scenarioTests = new HashSet<MethodTest>();
for (int i = 0; i < testNodes.getLength(); i++) {
String testQualifiedName = testNodes.item(i).getAttributes().getNamedItem("name").getNodeValue();
String testSimpleName = testQualifiedName.substring(testQualifiedName.lastIndexOf('.') + 1);
scenarioTests.add(new MethodTest(testQualifiedName, testSimpleName));
}
return scenarioTests;
} catch (Throwable t) {
throw new ExtractScenarioTestsException();
}
}
public String getAbsolutePath() {
return file.getAbsolutePath();
}
}