| //////////////////////////////////////////////////////////////////////////////// |
| // checkstyle: Checks Java source code for adherence to a set of rules. |
| // Copyright (C) 2001-2017 the original author or authors. |
| // |
| // This library is free software; you can redistribute it and/or |
| // modify it under the terms of the GNU Lesser General Public |
| // License as published by the Free Software Foundation; either |
| // version 2.1 of the License, or (at your option) any later version. |
| // |
| // This library is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| // Lesser General Public License for more details. |
| // |
| // You should have received a copy of the GNU Lesser General Public |
| // License along with this library; if not, write to the Free Software |
| // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package com.puppycrawl.tools.checkstyle; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.parsers.SAXParserFactory; |
| |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| import org.xml.sax.XMLReader; |
| import org.xml.sax.helpers.DefaultHandler; |
| |
| /** |
| * Contains the common implementation of a loader, for loading a configuration |
| * from an XML file. |
| * <p> |
| * The error handling policy can be described as being austere, dead set, |
| * disciplinary, dour, draconian, exacting, firm, forbidding, grim, hard, hard- |
| * boiled, harsh, harsh, in line, iron-fisted, no-nonsense, oppressive, |
| * persnickety, picky, prudish, punctilious, puritanical, rigid, rigorous, |
| * scrupulous, set, severe, square, stern, stickler, straight, strait-laced, |
| * stringent, stuffy, stuffy, tough, unpermissive, unsparing and uptight. |
| * </p> |
| * |
| * @author Oliver Burn |
| * @noinspection ThisEscapedInObjectConstruction |
| */ |
| public class XmlLoader |
| extends DefaultHandler { |
| /** Maps public id to resolve to resource name for the DTD. */ |
| private final Map<String, String> publicIdToResourceNameMap; |
| /** Parser to read XML files. **/ |
| private final XMLReader parser; |
| |
| /** |
| * Creates a new instance. |
| * @param publicId the public ID for the DTD to resolve |
| * @param dtdResourceName the resource for the DTD |
| * @throws SAXException if an error occurs |
| * @throws ParserConfigurationException if an error occurs |
| */ |
| protected XmlLoader(String publicId, String dtdResourceName) |
| throws SAXException, ParserConfigurationException { |
| this(new HashMap<>(1)); |
| publicIdToResourceNameMap.put(publicId, dtdResourceName); |
| } |
| |
| /** |
| * Creates a new instance. |
| * @param publicIdToResourceNameMap maps public IDs to DTD resource names |
| * @throws SAXException if an error occurs |
| * @throws ParserConfigurationException if an error occurs |
| */ |
| protected XmlLoader(Map<String, String> publicIdToResourceNameMap) |
| throws SAXException, ParserConfigurationException { |
| this.publicIdToResourceNameMap = new HashMap<>(publicIdToResourceNameMap); |
| final SAXParserFactory factory = SAXParserFactory.newInstance(); |
| FeaturesForVerySecureJavaInstallations.addFeaturesForVerySecureJavaInstallations(factory); |
| factory.setValidating(true); |
| factory.setNamespaceAware(true); |
| parser = factory.newSAXParser().getXMLReader(); |
| parser.setContentHandler(this); |
| parser.setEntityResolver(this); |
| parser.setErrorHandler(this); |
| } |
| |
| /** |
| * Parses the specified input source. |
| * @param inputSource the input source to parse. |
| * @throws IOException if an error occurs |
| * @throws SAXException in an error occurs |
| */ |
| public void parseInputSource(InputSource inputSource) |
| throws IOException, SAXException { |
| parser.parse(inputSource); |
| } |
| |
| @Override |
| public InputSource resolveEntity(String publicId, String systemId) |
| throws SAXException, IOException { |
| final InputSource inputSource; |
| if (publicIdToResourceNameMap.keySet().contains(publicId)) { |
| final String dtdResourceName = |
| publicIdToResourceNameMap.get(publicId); |
| final ClassLoader loader = |
| getClass().getClassLoader(); |
| final InputStream dtdIs = |
| loader.getResourceAsStream(dtdResourceName); |
| |
| inputSource = new InputSource(dtdIs); |
| } |
| else { |
| inputSource = super.resolveEntity(publicId, systemId); |
| } |
| return inputSource; |
| } |
| |
| @Override |
| public void error(SAXParseException exception) throws SAXException { |
| throw exception; |
| } |
| |
| @Override |
| public void fatalError(SAXParseException exception) throws SAXException { |
| throw exception; |
| } |
| |
| /** |
| * Used for setting specific for secure java installations features to SAXParserFactory. |
| * Pulled out as a separate class in order to suppress Pitest mutations. |
| */ |
| public static final class FeaturesForVerySecureJavaInstallations { |
| /** Feature that enables loading external DTD when loading XML files. */ |
| private static final String LOAD_EXTERNAL_DTD = |
| "http://apache.org/xml/features/nonvalidating/load-external-dtd"; |
| /** Feature that enables including external general entities in XML files. */ |
| private static final String EXTERNAL_GENERAL_ENTITIES = |
| "http://xml.org/sax/features/external-general-entities"; |
| |
| /** Stop instances being created. **/ |
| private FeaturesForVerySecureJavaInstallations() { |
| } |
| |
| /** |
| * Configures SAXParserFactory with features required |
| * for execution on very secured environments. |
| * @param factory factory to be configured with special features |
| * @throws SAXException if an error occurs |
| * @throws ParserConfigurationException if an error occurs |
| */ |
| public static void addFeaturesForVerySecureJavaInstallations(SAXParserFactory factory) |
| throws SAXException, ParserConfigurationException { |
| factory.setFeature(LOAD_EXTERNAL_DTD, true); |
| factory.setFeature(EXTERNAL_GENERAL_ENTITIES, true); |
| } |
| } |
| } |