/* * Copyright 2013 Matt Sicker and Contributors * * Licensed 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. */ package atg.tools.dynunit.junit.nucleus; import atg.nucleus.logging.ApplicationLoggingImpl; import atg.xml.tools.DefaultErrorHandler; import atg.xml.tools.DefaultXMLToolsFactory; import atg.xml.tools.XMLToDOMParser; import atg.xml.tools.XMLToolsFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.LinkedList; import java.util.List; /** * A utility class to help with common XML manipulation functions. * * @version 1.0 */ public class XmlUtils { private static final Logger log = LogManager.getLogger(); /** * Initializes the XML file to be parsed and gets the Document tree for it. * * @param pXmlFile the XML file to parse * @param pValidateDoc true if the file should be validated against its DTD; otherwise false. * * @throws FileNotFoundException if the specified file can not be located. * @throws Exception if an error occurs parsing the file to a DOM. */ public static Document initializeFile(File pXmlFile, boolean pValidateDoc) throws Exception { XMLToolsFactory factory = DefaultXMLToolsFactory.getInstance(); XMLToDOMParser parser = factory.createXMLToDOMParser(); // XXX: god damn logging ApplicationLoggingImpl logger = new ApplicationLoggingImpl( "[UnitTests.base:atg.junit.nucleus.XmlUtils]" ); DefaultErrorHandler errorHandler = new DefaultErrorHandler(logger, true, true); return parser.parse(new FileInputStream(pXmlFile), pValidateDoc, errorHandler); } /** * retrieves the Node(s) represented within the DOM hierarchy at the location * designated by the 'nested' child nodes. * * @param pXmlFile the XML document in which to look * @param pValidateDoc true if the file should be validated against its DTD; otherwise false. * @param pChildren the nested child nodes to retrieve. for example, if you specified * an array { "foo", "bar", "flippy" } this method would return all * 'flippy' * Nodes for the XML * document: * <pre> * * <foo< * * <bar< * * <flippy * .../< * * <flippy * .../< * * </bar< * * </foo< * * </pre> * * @return List the requested child Nodes. an empty List if no child Nodes exist. * @throws FileNotFoundException if the specified file can not be located. * @throws Exception if an error occurs parsing the file to a DOM. */ public static List<Node> getNodes(File pXmlFile, boolean pValidateDoc, String[] pChildren) throws Exception { return getNodes(initializeFile(pXmlFile, pValidateDoc), pChildren); } /** * retrieves the Node(s) represented within the DOM hierarchy at the location * designated by the 'nested' child nodes. * * @param pDocument the XML document parsed to a DOM * @param pChildren the nested child nodes to retrieve. for example, if you specified * an array { "foo", "bar", "flippy" } this method would return all 'flippy' * Nodes for the XML * document: * <pre> * * <foo< * * <bar< * * <flippy .../< * * <flippy .../< * * </bar< * * </foo< * </pre> * * @return List the requested child Nodes. an empty List if no child Nodes exist. * null if the specified Document was null. */ public static List<Node> getNodes(@Nullable Document pDocument, String[] pChildren) { if ( pDocument == null ) { return null; } return getNodes(pDocument.getDocumentElement(), pChildren); } /** * retrieves the Node(s) represented within the DOM hierarchy at the location * designated by the 'nested' child nodes. * * @param pNode the Node at which to start searching * @param pChildren the nested child nodes to retrieve. for example, if you specified * an array { "foo", "bar", "flippy" } this method would return all 'flippy' * Nodes for the XML * document: * <pre> * * <foo< * * <bar< * * <flippy .../< * * <flippy .../< * * </bar< * * </foo< * </pre> * * @return List the requested child Nodes. an empty List if no child Nodes exist. */ public static List<Node> getNodes(Node pNode, String[] pChildren) { List<Node> nodes = new LinkedList<Node>(); if ( pNode == null ) { // do nothing } else if ( pChildren == null || pChildren.length == 0 ) { // if there are no more children, just return this Node nodes.add(pNode); } else { // otherwise recurse and get the children nodes... String[] children = new String[pChildren.length - 1]; System.arraycopy(pChildren, 1, children, 0, children.length); NodeList nl = ((Element) pNode).getElementsByTagName(pChildren[0]); for ( int i = 0; i < nl.getLength(); i++ ) { nodes.addAll(getNodes(nl.item(i), children)); } } return nodes; } /** * returns the Element NodeList for the specified child of the parent Node. * * @param pNode the parent node * @param pChild the name of the child node(s) * * @return NodeList the children of the parent Node. null if pChild or pNode is null. */ public static NodeList getNodes(Node pNode, String pChild) { if ( pNode == null || pChild == null ) { return null; } return ((Element) pNode).getElementsByTagName(pChild); } /** * Returns the String value of the content of the Node specified. * * @param pElement the node whose content to get. * * @return the value of the content of the Node. An empty String if the Node * does not have any content. */ public static String getNodeTextValue(Node pElement) { NodeList children = pElement.getChildNodes(); StringBuilder sb = new StringBuilder(); for ( int i = 0; i < children.getLength(); i++ ) { if ( children.item(i) instanceof Text ) { Text n = (Text) children.item(i); sb.append(n.getNodeValue()); } } return sb.toString(); } /** * gets the value of the named attribute. * * @param pNode the node whose attribute should be retrieved. * @param pName the name of attribute whose value should be retrieved. * * @return the value of the attribute. null if the attribute is not defined * or if a value has not been specified for it. */ public static String getAttribute(Node pNode, String pName) { return getAttribute(pNode, pName, null); } /** * returns the value of the named attribute, or the specified default if the attribute * value is null. * * @param pNode the node whose attribute should be retrieved. * @param pName the name of attribute whose value should be retrieved. * @param pDefault the default value to return if a value does not exist for the specified * attribute, or if the specified attribute is not defined in this Node. * * @return the value of the attribute. */ public static String getAttribute(Node pNode, String pName, String pDefault) { if ( pNode.getAttributes().getNamedItem(pName) == null ) { return pDefault; } return pNode.getAttributes().getNamedItem(pName).getNodeValue(); } /** * returns the value of the named attribute as an Integer object. * * @param pNode the node whose attribute should be retrieved. * @param pName the name of attribute whose value should be retrieved. * @param pAllowNull the default value to return if a value does not exist for the specified * attribute, or if the specified attribute is not defined in this Node. * * @return the value of the attribute. If pAllowNull is true and * no value is specified for the attribute then null is returned. * @throws FileFormatException if the value specified by the attribute can not be converted to * an Integer, * or if pAllowNull is false and no value was specified for the * attribute. */ public static Integer getIntegerAttribute(Node pNode, String pName, boolean pAllowNull) throws FileFormatException { Node n = pNode.getAttributes().getNamedItem(pName); if ( n == null && pAllowNull ) { return null; } if ( n == null ) { throw new FileFormatException( "No value specified for required attribute '" + pName + "'." ); } return getIntegerValue(n.getNodeValue(), pName, pAllowNull); } /** * converts the specified String into an Integer. * * @param pValue the value to convert. * @param pDescriptor a descriptor of what the value is for. * @param pAllowNull true if the input value can be null; otherwise false. * * @return the Integer value of the String input value. * @throws FileFormatException if the String can not be converted to an Integer or if it is * null and pAllowNull is false. */ public static Integer getIntegerValue(String pValue, String pDescriptor, boolean pAllowNull) throws FileFormatException { if ( (pValue == null || pValue.trim().length() == 0) && pAllowNull ) { return null; } try { return new Integer(pValue != null ? pValue.trim() : null); } catch ( Throwable t ) { throw new FileFormatException( "Invalid Integer value '" + pValue + "' specified for attribute '" + pDescriptor + "'." ); } } /** * returns the value of the named attribute as a Long object. * * @param pNode the node whose attribute should be retrieved. * @param pName the name of attribute whose value should be retrieved. * @param pAllowNull [FIXME] the default value to return if a value does not exist for the * specified * attribute, or if the specified attribute is not defined in this Node. * * @return Long the value of the attribute. If pAllowNull is true and * no value is specified for the attribute then null is returned. * @throws FileFormatException if the value specified by the attribute can not be converted to * a Long, * or if pAllowNull is false and no value was specified for the * attribute. */ public static Long getLongAttribute(Node pNode, String pName, boolean pAllowNull) throws FileFormatException { Node n = pNode.getAttributes().getNamedItem(pName); if ( n == null && pAllowNull ) { return null; } if ( n == null ) { throw new FileFormatException( "No value specified for required attribute '" + pName + "'." ); } return getLongValue(n.getNodeValue(), pName, pAllowNull); } /** * converts the specified String into a Long. * * @param pValue the value to convert. * @param pDescriptor a descriptor of what the value is for. * @param pAllowNull true if the input value can be null; otherwise false. * * @return the Long value of the String input value. * @throws FileFormatException if the String can not be converted to a Long or if it is * null and pAllowNull is false. */ public static Long getLongValue(String pValue, String pDescriptor, boolean pAllowNull) throws FileFormatException { // TODO: StringUtils.trimToNull() would be great for this if ( (pValue == null || pValue.trim().length() == 0) && pAllowNull ) { return null; } try { return new Long(pValue != null ? pValue.trim() : null); } catch ( Throwable t ) { throw new FileFormatException( "Invalid Long value '" + pValue + "' specified for attribute '" + pDescriptor + "'." ); } } /** * returns the value of the named attribute as a boolean. * * @param pNode the node whose attribute should be retrieved. * @param pName the name of attribute whose value should be retrieved. * @param pDefault the default value to return if a value does not exist for the specified * attribute, or if the specified attribute is not defined in this Node. * * @return boolean the value of the attribute. If no value was specified for the * attribute then the default value is returned. * @throws FileFormatException if the value specified by the attribute can not be converted to * a boolean. */ public static boolean getBooleanAttribute(Node pNode, String pName, boolean pDefault) throws FileFormatException { Node n = pNode.getAttributes().getNamedItem(pName); if ( n == null ) { return pDefault; } return getBooleanValue(n.getNodeValue(), pName, pDefault); } /** * converts the specified value into a boolean. * * @param pValue the value which should be converted. * @param pDescriptor a descriptor of what the value is for. * @param pDefault the default value to return if the specified value is null or empty. * * @return boolean the converted value. If the specified value was null or empty * then the default value is returned. * @throws FileFormatException if the specified value can not be converted to a boolean. */ public static boolean getBooleanValue(String pValue, String pDescriptor, boolean pDefault) throws FileFormatException { // XXX: what the fuck if ( pValue == null || pValue.trim().length() == 0 ) { return pDefault; } if ( !pValue.trim().equalsIgnoreCase("true") && !pValue.trim().equalsIgnoreCase("false") ) { throw new FileFormatException( "Invalid Boolean value '" + pValue + "' specified for attribute '" + pDescriptor + "'. Must be [true|false]" ); } return Boolean.parseBoolean(pValue.trim()); } /** * returns the value of the named attribute as a Boolean object. * * @param pNode the node whose attribute should be retrieved. * @param pName the name of attribute whose value should be retrieved. * @param pDefault the default value to return if a value does not exist for the specified * attribute, or if the specified attribute is not defined in this Node. * * @return Boolean the value of the attribute. If no value was specified for the * attribute then the default value is returned. * @throws FileFormatException if the value specified by the attribute can not be converted to * a boolean. */ public static Boolean getBooleanAttribute(Node pNode, String pName, Boolean pDefault) throws FileFormatException { Node n = pNode.getAttributes().getNamedItem(pName); if ( n == null ) { return pDefault; } String v = n.getNodeValue(); if ( v == null || v.length() == 0 ) { return pDefault; } return getBooleanValue( v, pName, true ); // the default 'true' passed to this call should not never to be used } /* a main method for testing these functions */ public static void main(String[] pArgs) { String file = "C:\\temp\\registry.xml"; //String file = "/work/systest/qma/temp/registry.xml"; log.info("BEA's registry file: [{}]", file); String[] children = { "host", "product", "release" }; try { List<Node> nodes = getNodes(new File(file), false, children); if ( nodes == null ) { log.error("Nodes is null."); } else if ( nodes.size() == 0 ) { log.error("Nodes is empty."); } else { for ( Node n : nodes ) { log.info( "Got Node: {}/{}", getAttribute(n, "level"), getAttribute(n, "ServicePackLevel") ); } } } catch ( Throwable t ) { log.catching(t); } log.info("-------------------"); log.info("BEA Version: " + TestUtils.getBeaVersion()); //System.setProperty("bea.home","c:\\bea"); //log.info("BEA Version: " + atg.junit.nucleus.TestUtils.getBeaVersion() ); } }