001/*
002 *   Copyright 2020 Vonage
003 *
004 *   Licensed under the Apache License, Version 2.0 (the "License");
005 *   you may not use this file except in compliance with the License.
006 *   You may obtain a copy of the License at
007 *
008 *        http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *   Unless required by applicable law or agreed to in writing, software
011 *   distributed under the License is distributed on an "AS IS" BASIS,
012 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *   See the License for the specific language governing permissions and
014 *   limitations under the License.
015 */
016package com.vonage.client.legacyutils;
017
018import com.vonage.client.VonageResponseParseException;
019import org.w3c.dom.Document;
020
021import javax.xml.parsers.DocumentBuilder;
022import javax.xml.parsers.DocumentBuilderFactory;
023import javax.xml.parsers.ParserConfigurationException;
024import java.util.concurrent.locks.Lock;
025import java.util.concurrent.locks.ReentrantLock;
026
027public class XmlParser {
028    /**
029     * A lock associated with {@link #documentBuilder}.
030     */
031    private final Lock documentBuilderLock = new ReentrantLock();
032
033    /**
034     * Used for parsing XML data.
035     *
036     * Do not use this without locking on {@link #documentBuilderLock}
037     */
038    private DocumentBuilder documentBuilder;
039
040    /**
041     * Parse a provided XML String and return the generated DOM Document.
042     *
043     * @param xml A String containing XML.
044     * @return A Document generated from the parsed XML.
045     * @throws VonageResponseParseException If there is a problem initializing the XML parser or parsing the XML.
046     */
047    public Document parseXml(String xml) throws VonageResponseParseException {
048        // TODO: Maybe an Error subclass for XML initialization errors, as these are serious and unexpected.
049        Document doc;
050        this.documentBuilderLock.lock();
051        try {
052            if (this.documentBuilder == null) {
053                DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
054                this.documentBuilder = documentBuilderFactory.newDocumentBuilder();
055            }
056            doc = XmlUtil.parseXmlString(this.documentBuilder, xml);
057        } catch (ParserConfigurationException e) {
058            throw new VonageResponseParseException("Exception initialing XML parser", e);
059        } finally {
060            this.documentBuilderLock.unlock();
061        }
062        return doc;
063    }
064}