001////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code for adherence to a set of rules.
003// Copyright (C) 2001-2014  Oliver Burn
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018////////////////////////////////////////////////////////////////////////////////
019package com.puppycrawl.tools.checkstyle.api;
020
021import com.google.common.collect.Maps;
022import java.io.IOException;
023import java.io.InputStream;
024import java.util.HashMap;
025import java.util.Map;
026import javax.xml.parsers.ParserConfigurationException;
027import javax.xml.parsers.SAXParserFactory;
028import org.xml.sax.InputSource;
029import org.xml.sax.SAXException;
030import org.xml.sax.SAXParseException;
031import org.xml.sax.XMLReader;
032import org.xml.sax.helpers.DefaultHandler;
033
034/**
035 * Contains the common implementation of a loader, for loading a configuration
036 * from an XML file.
037 * <p>
038 * The error handling policy can be described as being austere, dead set,
039 * disciplinary, dour, draconian, exacting, firm, forbidding, grim, hard, hard-
040 * boiled, harsh, harsh, in line, iron-fisted, no-nonsense, oppressive,
041 * persnickety, picky, prudish, punctilious, puritanical, rigid, rigorous,
042 * scrupulous, set, severe, square, stern, stickler, straight, strait-laced,
043 * stringent, stuffy, stuffy, tough, unpermissive, unsparing and uptight.
044 * </p>
045 *
046 * @author Oliver Burn
047 */
048public abstract class AbstractLoader
049    extends DefaultHandler
050{
051    /** maps public id to resolve to esource name for the DTD */
052    private final Map<String, String> publicIdToResourceNameMap;
053    /** parser to read XML files **/
054    private final XMLReader parser;
055
056    /**
057     * Creates a new instance.
058     * @param publicId the public ID for the DTD to resolve
059     * @param dtdResourceName the resource for the DTD
060     * @throws SAXException if an error occurs
061     * @throws ParserConfigurationException if an error occurs
062     */
063    protected AbstractLoader(String publicId, String dtdResourceName)
064        throws SAXException, ParserConfigurationException
065    {
066        this(new HashMap<String, String>(1));
067        publicIdToResourceNameMap.put(publicId, dtdResourceName);
068    }
069
070    /**
071     * Creates a new instance.
072     * @param publicIdToResourceNameMap maps public IDs to DTD resource names
073     * @throws SAXException if an error occurs
074     * @throws ParserConfigurationException if an error occurs
075     */
076    protected AbstractLoader(Map<String, String> publicIdToResourceNameMap)
077        throws SAXException, ParserConfigurationException
078    {
079        this.publicIdToResourceNameMap =
080            Maps.newHashMap(publicIdToResourceNameMap);
081        final SAXParserFactory factory = SAXParserFactory.newInstance();
082        factory.setValidating(true);
083        factory.setNamespaceAware(true);
084        parser = factory.newSAXParser().getXMLReader();
085        parser.setContentHandler(this);
086        parser.setEntityResolver(this);
087        parser.setErrorHandler(this);
088    }
089
090    /**
091     * Parses the specified input source.
092     * @param inputSource the input source to parse.
093     * @throws IOException if an error occurs
094     * @throws SAXException in an error occurs
095     */
096    public void parseInputSource(InputSource inputSource)
097        throws IOException, SAXException
098    {
099        parser.parse(inputSource);
100    }
101
102    @Override
103    public InputSource resolveEntity(String publicId, String systemId)
104        throws SAXException, IOException
105    {
106        if (publicIdToResourceNameMap.keySet().contains(publicId)) {
107            final String dtdResourceName =
108                    publicIdToResourceNameMap.get(publicId);
109            final ClassLoader loader =
110                this.getClass().getClassLoader();
111            final InputStream dtdIS =
112                loader.getResourceAsStream(dtdResourceName);
113            if (dtdIS == null) {
114                throw new SAXException(
115                    "Unable to load internal dtd " + dtdResourceName);
116            }
117            return new InputSource(dtdIS);
118        }
119        return super.resolveEntity(publicId, systemId);
120    }
121
122    @Override
123    public void warning(SAXParseException ex) throws SAXException
124    {
125        throw ex;
126    }
127
128    @Override
129    public void error(SAXParseException ex) throws SAXException
130    {
131        throw ex;
132    }
133
134    @Override
135    public void fatalError(SAXParseException ex) throws SAXException
136    {
137        throw ex;
138    }
139}