/******************************************************************************* * Copyright 2017 Capital One Services, LLC and Bitwise, Inc. * 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 hydrograph.ui.engine.xpath; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; 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 javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.slf4j.Logger; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import hydrograph.ui.common.util.Constants; import hydrograph.ui.engine.util.ConverterUtil; import hydrograph.ui.logging.factory.LogFactory; /** * The class ComponentXpath * <p> * Used to create XPath objects for UI components. * * @author Bitwise * */ public class ComponentXpath { private static final Logger LOGGER = LogFactory.INSTANCE.getLogger(ConverterUtil.class); public static final ComponentXpath INSTANCE = new ComponentXpath(); private Map<String, ComponentsAttributeAndValue> xpathMap; private Document doc; public Map<String, ComponentsAttributeAndValue> getXpathMap() { if (xpathMap == null) { xpathMap = new HashMap<String, ComponentsAttributeAndValue>(); } return xpathMap; } /** * Adds the parameters in the Target XML. * * @param out * the out * @return the byte array output stream */ public ByteArrayOutputStream addParameters(ByteArrayOutputStream out) { ByteArrayInputStream inputStream = new ByteArrayInputStream(out.toByteArray()); try { XPath xPath = createXPathInstance(inputStream, null); LOGGER.debug("GENRATED COMPONENTS XPATH {}", getXpathMap().toString()); for (Map.Entry<String, ComponentsAttributeAndValue> entry : getXpathMap().entrySet()) { NodeList nodeList = (NodeList) xPath.compile(entry.getKey()).evaluate(doc, XPathConstants.NODESET); if(entry.getValue().isNewNode()) addParameterAsNewNode(entry, nodeList,entry.getValue().hasEmptyNode()); else addParameterAsAttribute(entry, nodeList); } TransformerFactory transformerFactory = TransformerFactory.newInstance(); transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); Transformer transformer = transformerFactory.newTransformer(); DOMSource source = new DOMSource(doc); out.reset(); StreamResult result = new StreamResult(out); transformer.transform(source, result); getXpathMap().clear(); } catch (ParserConfigurationException | SAXException | IOException | XPathExpressionException | TransformerException e) { LOGGER.error("Exception occurred while parametrizing the XML", e); } finally { try { inputStream.close(); } catch (IOException ioe) { LOGGER.error("Exception occurred while closing input stream", ioe); } } return out; } private void addParameterAsAttribute(Map.Entry<String, ComponentsAttributeAndValue> entry,NodeList nodeList) { for (int i = 0; i < nodeList.getLength(); i++) { Node nNode = nodeList.item(i); if (Node.ELEMENT_NODE == nNode.getNodeType()) { Element eElement = (Element) nNode; eElement.setAttribute(entry.getValue().getAttributeName(), entry.getValue().getAttributeValue()); } } } private void addParameterAsNewNode(Map.Entry<String, ComponentsAttributeAndValue> entry,NodeList nodeList,boolean removeEmtyNode) { Node cloneNode=null; Node nNode=null; Node parentNode = null; try { for (int i = 0; i < nodeList.getLength(); i++) { parentNode = nodeList.item(i); if(parentNode!=null){ NodeList nNodeLst = (NodeList) nodeList.item(i); for (int j = 0; j < nNodeLst.getLength(); j++) { nNode = nNodeLst.item(j); cloneNode = nNode.cloneNode(false); cloneNode.setTextContent(entry.getValue().getNewNodeText()); } if(cloneNode!=null) parentNode.appendChild(cloneNode); }} // Remove empty node if (removeEmtyNode) for (int i = 0; i < nodeList.getLength(); i++) { parentNode = nodeList.item(i); NodeList nNodeLst = (NodeList) nodeList.item(i); nNode = nNodeLst.item(0); Node remove = nNode.getNextSibling(); parentNode.removeChild(remove); } } catch (DOMException exception) { LOGGER.error("Exception occured", exception); } } /** * Creates the Xpath instance. * * @param inputStream * the input stream * @param file * the file * @return the x path * @throws ParserConfigurationException * the parser configuration exception * @throws SAXException * the SAX exception * @throws IOException * Signals that an I/O exception has occurred. */ public XPath createXPathInstance(ByteArrayInputStream inputStream, File file) throws ParserConfigurationException, SAXException, IOException { LOGGER.debug("Invoking X-Path instance"); XPath xPath = null; DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); dbFactory.setFeature(Constants.DISALLOW_DOCTYPE_DECLARATION, true); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); if (inputStream != null) doc = dBuilder.parse(inputStream); else if (file != null) { doc = dBuilder.parse(file); } doc.getDocumentElement().normalize(); Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); xPath = XPathFactory.newInstance().newXPath(); return xPath; } }