Coverage Report - com.puppycrawl.tools.checkstyle.PackageNamesLoader
 
Classes in this File Line Coverage Branch Coverage Complexity
PackageNamesLoader
100%
41/41
100%
12/12
3
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2017 the original author or authors.
 4  
 //
 5  
 // This library is free software; you can redistribute it and/or
 6  
 // modify it under the terms of the GNU Lesser General Public
 7  
 // License as published by the Free Software Foundation; either
 8  
 // version 2.1 of the License, or (at your option) any later version.
 9  
 //
 10  
 // This library is distributed in the hope that it will be useful,
 11  
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 // Lesser General Public License for more details.
 14  
 //
 15  
 // You should have received a copy of the GNU Lesser General Public
 16  
 // License along with this library; if not, write to the Free Software
 17  
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 18  
 ////////////////////////////////////////////////////////////////////////////////
 19  
 
 20  
 package com.puppycrawl.tools.checkstyle;
 21  
 
 22  
 import java.io.BufferedInputStream;
 23  
 import java.io.IOException;
 24  
 import java.io.InputStream;
 25  
 import java.net.URL;
 26  
 import java.util.ArrayDeque;
 27  
 import java.util.Deque;
 28  
 import java.util.Enumeration;
 29  
 import java.util.Iterator;
 30  
 import java.util.LinkedHashSet;
 31  
 import java.util.Set;
 32  
 
 33  
 import javax.xml.parsers.ParserConfigurationException;
 34  
 
 35  
 import org.xml.sax.Attributes;
 36  
 import org.xml.sax.InputSource;
 37  
 import org.xml.sax.SAXException;
 38  
 
 39  
 import com.google.common.io.Closeables;
 40  
 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
 41  
 import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
 42  
 
 43  
 /**
 44  
  * Loads a list of package names from a package name XML file.
 45  
  * @author Rick Giles
 46  
  */
 47  
 public final class PackageNamesLoader
 48  
     extends XmlLoader {
 49  
     /** The public ID for the configuration dtd. */
 50  
     private static final String DTD_PUBLIC_ID =
 51  
         "-//Puppy Crawl//DTD Package Names 1.0//EN";
 52  
 
 53  
     /** The resource for the configuration dtd. */
 54  
     private static final String DTD_RESOURCE_NAME =
 55  
         "com/puppycrawl/tools/checkstyle/packages_1_0.dtd";
 56  
 
 57  
     /** Name of default checkstyle package names resource file.
 58  
      * The file must be in the classpath.
 59  
      */
 60  
     private static final String CHECKSTYLE_PACKAGES =
 61  
         "checkstyle_packages.xml";
 62  
 
 63  
     /** Qualified name for element 'package'. */
 64  
     private static final String PACKAGE_ELEMENT_NAME = "package";
 65  
 
 66  
     /** The temporary stack of package name parts. */
 67  2036
     private final Deque<String> packageStack = new ArrayDeque<>();
 68  
 
 69  
     /** The fully qualified package names. */
 70  2036
     private final Set<String> packageNames = new LinkedHashSet<>();
 71  
 
 72  
     /**
 73  
      * Creates a new {@code PackageNamesLoader} instance.
 74  
      * @throws ParserConfigurationException if an error occurs
 75  
      * @throws SAXException if an error occurs
 76  
      */
 77  
     private PackageNamesLoader()
 78  
             throws ParserConfigurationException, SAXException {
 79  2036
         super(DTD_PUBLIC_ID, DTD_RESOURCE_NAME);
 80  2036
     }
 81  
 
 82  
     @Override
 83  
     public void startElement(String uri,
 84  
                              String localName,
 85  
                              String qName,
 86  
                              Attributes attributes) {
 87  20
         if (PACKAGE_ELEMENT_NAME.equals(qName)) {
 88  
             //push package name, name is mandatory attribute with not empty value by DTD
 89  19
             final String name = attributes.getValue("name");
 90  19
             packageStack.push(name);
 91  
         }
 92  20
     }
 93  
 
 94  
     /**
 95  
      * Creates a full package name from the package names on the stack.
 96  
      * @return the full name of the current package.
 97  
      */
 98  
     private String getPackageName() {
 99  19
         final StringBuilder buf = new StringBuilder(256);
 100  19
         final Iterator<String> iterator = packageStack.descendingIterator();
 101  69
         while (iterator.hasNext()) {
 102  50
             final String subPackage = iterator.next();
 103  50
             buf.append(subPackage);
 104  50
             if (!CommonUtils.endsWithChar(subPackage, '.') && iterator.hasNext()) {
 105  31
                 buf.append('.');
 106  
             }
 107  50
         }
 108  19
         return buf.toString();
 109  
     }
 110  
 
 111  
     @Override
 112  
     public void endElement(String uri,
 113  
                            String localName,
 114  
                            String qName) {
 115  20
         if (PACKAGE_ELEMENT_NAME.equals(qName)) {
 116  
 
 117  19
             packageNames.add(getPackageName());
 118  19
             packageStack.pop();
 119  
         }
 120  20
     }
 121  
 
 122  
     /**
 123  
      * Returns the set of package names, compiled from all
 124  
      * checkstyle_packages.xml files found on the given class loaders
 125  
      * classpath.
 126  
      * @param classLoader the class loader for loading the
 127  
      *          checkstyle_packages.xml files.
 128  
      * @return the set of package names.
 129  
      * @throws CheckstyleException if an error occurs.
 130  
      */
 131  
     public static Set<String> getPackageNames(ClassLoader classLoader)
 132  
             throws CheckstyleException {
 133  
 
 134  
         final Set<String> result;
 135  
         try {
 136  
             //create the loader outside the loop to prevent PackageObjectFactory
 137  
             //being created anew for each file
 138  2034
             final PackageNamesLoader namesLoader = new PackageNamesLoader();
 139  
 
 140  2034
             final Enumeration<URL> packageFiles = classLoader.getResources(CHECKSTYLE_PACKAGES);
 141  
 
 142  2033
             while (packageFiles.hasMoreElements()) {
 143  2
                 processFile(packageFiles.nextElement(), namesLoader);
 144  
             }
 145  
 
 146  2031
             result = namesLoader.packageNames;
 147  
         }
 148  1
         catch (IOException ex) {
 149  1
             throw new CheckstyleException("unable to get package file resources", ex);
 150  
         }
 151  1
         catch (ParserConfigurationException | SAXException ex) {
 152  1
             throw new CheckstyleException("unable to open one of package files", ex);
 153  2031
         }
 154  
 
 155  2031
         return result;
 156  
     }
 157  
 
 158  
     /**
 159  
      * Reads the file provided and parses it with package names loader.
 160  
      * @param packageFile file from package
 161  
      * @param namesLoader package names loader
 162  
      * @throws SAXException if an error while parsing occurs
 163  
      * @throws CheckstyleException if unable to open file
 164  
      */
 165  
     private static void processFile(URL packageFile, PackageNamesLoader namesLoader)
 166  
             throws SAXException, CheckstyleException {
 167  3
         InputStream stream = null;
 168  
         try {
 169  3
             stream = new BufferedInputStream(packageFile.openStream());
 170  3
             final InputSource source = new InputSource(stream);
 171  3
             namesLoader.parseInputSource(source);
 172  
         }
 173  1
         catch (IOException ex) {
 174  1
             throw new CheckstyleException("unable to open " + packageFile, ex);
 175  
         }
 176  
         finally {
 177  3
             Closeables.closeQuietly(stream);
 178  1
         }
 179  1
     }
 180  
 }