Java tutorial
package org.apache.ddlutils; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.dbcp.BasicDataSource; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; import org.xml.sax.InputSource; /** * Creates a test summary snippet that can be put onto the DdlUtils web site. * * @version $Revision: $ */ public class TestSummaryCreatorTask extends Task { /** The DdlUtils version. */ private String _version; /** The file to write the snippet to. */ private File _outputFile; /** The input files. */ private ArrayList _fileSets = new ArrayList(); /** * Set the DdlUtils version used to run the tests. * * @param version The version */ public void setVersion(String version) { _version = version; } /** * Set the output file. * * @param outputFile The output file */ public void setOutputFile(File outputFile) { _outputFile = outputFile; } /** * Adds a fileset. * * @param fileset The additional input files */ public void addConfiguredFileset(FileSet fileset) { _fileSets.add(fileset); } /** * Returns the list of input files ({@link java.io.File} objects) to process. * Note that this does not check that the file is a valid and useful XML file. * * @return The input files */ private List getInputFiles() { ArrayList result = new ArrayList(); for (Iterator it = _fileSets.iterator(); it.hasNext();) { FileSet fileSet = (FileSet) it.next(); File fileSetDir = fileSet.getDir(getProject()); DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject()); String[] files = scanner.getIncludedFiles(); for (int idx = 0; (files != null) && (idx < files.length); idx++) { File file = new File(fileSetDir, files[idx]); if (file.isFile() && file.canRead()) { result.add(file); } } } return result; } /** * Processes all input files and gathers the relevant data. * * @return The Dom4j document object containing the summary */ private Document processInputFiles() throws IOException { Document summaryDoc = DocumentHelper.createDocument(); summaryDoc.addElement("summary"); for (Iterator it = getInputFiles().iterator(); it.hasNext();) { processInputFile(summaryDoc, (File) it.next()); } return summaryDoc; } /** * Returns the value of the specified attribute of the node determined by the given xpath. * * @param doc The XML document * @param xpath The xpath selecting the node whose attribute we want * @param attrName The name of the attribute * @return The attribute value */ private String getAttrValue(Document doc, String xpath, String attrName) { Node node = doc.selectSingleNode(xpath); if (node instanceof Attribute) { // we ignore the attribute name then return ((Attribute) node).getValue(); } else if (node != null) { return node.valueOf("@" + attrName); } else { return null; } } /** * Processes the given input file. * * @param summaryDoc The document object to add data to * @param inputFile The input file */ private void processInputFile(Document summaryDoc, File inputFile) throws IOException { try { // First we check whether it is an XML file SAXReader reader = new SAXReader(); Document testDoc = reader.read(new InputSource(new FileReader(inputFile))); // Then we check whether it is one that we're interested in if (testDoc.selectSingleNode("/testsuite") == null) { return; } // Ok, it is, so lets extract the data that we want: Element generalElement = (Element) summaryDoc.selectSingleNode("//general"); int totalNumTests = 0; int totalNumErrors = 0; int totalNumFailures = 0; if (generalElement == null) { generalElement = summaryDoc.getRootElement().addElement("general"); // General run info (we only need this once) generalElement.addAttribute("ddlUtilsVersion", _version); generalElement.addAttribute("date", getAttrValue(testDoc, "//property[@name='TODAY']", "value")); generalElement.addAttribute("lang", getAttrValue(testDoc, "//property[@name='env.LANG']", "value")); generalElement.addAttribute("jre", getAttrValue(testDoc, "//property[@name='java.runtime.name']", "value") + " " + getAttrValue(testDoc, "//property[@name='java.runtime.version']", "value") + " (" + getAttrValue(testDoc, "//property[@name='java.vendor']", "value") + ")"); generalElement.addAttribute("os", getAttrValue(testDoc, "//property[@name='os.name']", "value") + " " + getAttrValue(testDoc, "//property[@name='os.version']", "value") + ", arch " + getAttrValue(testDoc, "//property[@name='os.arch']", "value")); addTargetDatabaseInfo(generalElement, getAttrValue(testDoc, "//property[@name='jdbc.properties.file']", "value")); } else { totalNumTests = Integer.parseInt(generalElement.attributeValue("tests")); totalNumErrors = Integer.parseInt(generalElement.attributeValue("errors")); totalNumFailures = Integer.parseInt(generalElement.attributeValue("failures")); } int numTests = Integer.parseInt(getAttrValue(testDoc, "/testsuite", "tests")); int numErrors = Integer.parseInt(getAttrValue(testDoc, "/testsuite", "errors")); int numFailures = Integer.parseInt(getAttrValue(testDoc, "/testsuite", "failures")); totalNumTests += numTests; totalNumErrors += numErrors; totalNumFailures += numFailures; generalElement.addAttribute("tests", String.valueOf(totalNumTests)); generalElement.addAttribute("errors", String.valueOf(totalNumErrors)); generalElement.addAttribute("failures", String.valueOf(totalNumFailures)); if ((numErrors > 0) || (numFailures > 0)) { Element testSuiteNode = (Element) testDoc.selectSingleNode("/testsuite"); String testSuiteName = testSuiteNode.attributeValue("name"); // since tests have failed, we add it to the summary for (Iterator it = testSuiteNode.selectNodes("testcase[failure or error]").iterator(); it .hasNext();) { Element failedTestElement = (Element) it.next(); Element newTestElement = summaryDoc.getRootElement().addElement("failedTest"); // Test setup failure, so the test was not actually run ? if (!failedTestElement.attributeValue("classname").startsWith("junit.framework.TestSuite")) { newTestElement.addAttribute("name", failedTestElement.attributeValue("classname") + "#" + failedTestElement.attributeValue("name")); } newTestElement.addAttribute("testsuite", testSuiteName); } } } catch (DocumentException ex) { // No, apparently it's not an XML document, so we ignore it } } /** * Adds the data from the test jdbc propertis file to the document. * * @param element The element to add the relevant database properties to * @param jdbcPropertiesFile The path of the properties file */ protected void addTargetDatabaseInfo(Element element, String jdbcPropertiesFile) throws IOException, BuildException { if (jdbcPropertiesFile == null) { return; } Properties props = readProperties(jdbcPropertiesFile); Connection conn = null; DatabaseMetaData metaData = null; try { String dataSourceClass = props.getProperty( TestAgainstLiveDatabaseBase.DATASOURCE_PROPERTY_PREFIX + "class", BasicDataSource.class.getName()); DataSource dataSource = (DataSource) Class.forName(dataSourceClass).newInstance(); for (Iterator it = props.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry) it.next(); String propName = (String) entry.getKey(); if (propName.startsWith(TestAgainstLiveDatabaseBase.DATASOURCE_PROPERTY_PREFIX) && !propName.equals(TestAgainstLiveDatabaseBase.DATASOURCE_PROPERTY_PREFIX + "class")) { BeanUtils.setProperty(dataSource, propName.substring(TestAgainstLiveDatabaseBase.DATASOURCE_PROPERTY_PREFIX.length()), entry.getValue()); } } String platformName = props.getProperty(TestAgainstLiveDatabaseBase.DDLUTILS_PLATFORM_PROPERTY); if (platformName == null) { platformName = new PlatformUtils().determineDatabaseType(dataSource); if (platformName == null) { throw new BuildException( "Could not determine platform from datasource, please specify it in the jdbc.properties via the ddlutils.platform property"); } } element.addAttribute("platform", platformName); element.addAttribute("dataSourceClass", dataSourceClass); conn = dataSource.getConnection(); metaData = conn.getMetaData(); try { element.addAttribute("dbProductName", metaData.getDatabaseProductName()); } catch (Throwable ex) { // we ignore it } try { element.addAttribute("dbProductVersion", metaData.getDatabaseProductVersion()); } catch (Throwable ex) { // we ignore it } try { int databaseMajorVersion = metaData.getDatabaseMajorVersion(); int databaseMinorVersion = metaData.getDatabaseMinorVersion(); element.addAttribute("dbVersion", databaseMajorVersion + "." + databaseMinorVersion); } catch (Throwable ex) { // we ignore it } try { element.addAttribute("driverName", metaData.getDriverName()); } catch (Throwable ex) { // we ignore it } try { element.addAttribute("driverVersion", metaData.getDriverVersion()); } catch (Throwable ex) { // we ignore it } try { int jdbcMajorVersion = metaData.getJDBCMajorVersion(); int jdbcMinorVersion = metaData.getJDBCMinorVersion(); element.addAttribute("jdbcVersion", jdbcMajorVersion + "." + jdbcMinorVersion); } catch (Throwable ex) { // we ignore it } } catch (Exception ex) { throw new BuildException(ex); } finally { if (conn != null) { try { conn.close(); } catch (SQLException ex) { // we ignore it } } } } /** * Reads the database properties from the used properties file. * * @param jdbcPropertiesFile The path of the properties file * @return The properties */ private Properties readProperties(String jdbcPropertiesFile) { Properties props = new Properties(); InputStream propStream = null; try { propStream = TestSummaryCreatorTask.class.getResourceAsStream(jdbcPropertiesFile); if (propStream == null) { // not on the classpath ? let's try a file File baseDir = getProject().getBaseDir(); File propFile = new File(baseDir, jdbcPropertiesFile); if (propFile.exists() && propFile.isFile() && propFile.canRead()) { propStream = new FileInputStream(propFile); } else { throw new BuildException("Cannot load test jdbc properties from file " + jdbcPropertiesFile); } } props.load(propStream); } catch (BuildException ex) { throw ex; } catch (Exception ex) { throw new BuildException("Cannot load test jdbc properties from file " + jdbcPropertiesFile, ex); } finally { if (propStream != null) { try { propStream.close(); } catch (IOException ex) { log("Could not close the stream used to read the test jdbc properties", Project.MSG_WARN); } } } return props; } /** * {@inheritDoc} */ public void execute() throws BuildException { try { log("Processing test results", Project.MSG_INFO); Document doc = processInputFiles(); XMLWriter writer = null; if (_outputFile != null) { writer = new XMLWriter(new FileWriter(_outputFile), OutputFormat.createPrettyPrint()); } else { writer = new XMLWriter(System.out, OutputFormat.createPrettyPrint()); } writer.write(doc); writer.close(); log("Processing finished", Project.MSG_INFO); } catch (Exception ex) { throw new BuildException("Error while processing the test results: " + ex.getLocalizedMessage(), ex); } } }