Coverage Report - com.puppycrawl.tools.checkstyle.checks.imports.ImportControlLoader
 
Classes in this File Line Coverage Branch Coverage Complexity
ImportControlLoader
88%
53/60
72%
26/36
3.714
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2014  Oliver Burn
 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  
 package com.puppycrawl.tools.checkstyle.checks.imports;
 20  
 
 21  
 import com.puppycrawl.tools.checkstyle.api.AbstractLoader;
 22  
 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
 23  
 import com.puppycrawl.tools.checkstyle.api.FastStack;
 24  
 import java.io.IOException;
 25  
 import java.io.InputStream;
 26  
 import java.net.MalformedURLException;
 27  
 import java.net.URI;
 28  
 import java.util.HashMap;
 29  
 import java.util.Map;
 30  
 import javax.xml.parsers.ParserConfigurationException;
 31  
 import org.xml.sax.Attributes;
 32  
 import org.xml.sax.InputSource;
 33  
 import org.xml.sax.SAXException;
 34  
 
 35  
 /**
 36  
  * Responsible for loading the contents of an import control configuration file.
 37  
  * @author Oliver Burn
 38  
  */
 39  1
 final class ImportControlLoader extends AbstractLoader
 40  
 {
 41  
     /** the public ID for the configuration dtd */
 42  
     private static final String DTD_PUBLIC_ID_1_0 =
 43  
         "-//Puppy Crawl//DTD Import Control 1.0//EN";
 44  
 
 45  
     /** the public ID for the configuration dtd */
 46  
     private static final String DTD_PUBLIC_ID_1_1 =
 47  
         "-//Puppy Crawl//DTD Import Control 1.1//EN";
 48  
 
 49  
     /** the resource for the configuration dtd */
 50  
     private static final String DTD_RESOURCE_NAME_1_0 =
 51  
         "com/puppycrawl/tools/checkstyle/checks/imports/import_control_1_0.dtd";
 52  
 
 53  
     /** the resource for the configuration dtd */
 54  
     private static final String DTD_RESOURCE_NAME_1_1 =
 55  
         "com/puppycrawl/tools/checkstyle/checks/imports/import_control_1_1.dtd";
 56  
 
 57  
     /** Used to hold the {@link PkgControl} objects. */
 58  7
     private final FastStack<PkgControl> mStack = FastStack.newInstance();
 59  
 
 60  
     /** the map to lookup the resource name by the id */
 61  1
     private static final Map<String, String> DTD_RESOURCE_BY_ID =
 62  
         new HashMap<String, String>();
 63  
 
 64  
     /** Initialise the map */
 65  
     static {
 66  1
         DTD_RESOURCE_BY_ID.put(DTD_PUBLIC_ID_1_0, DTD_RESOURCE_NAME_1_0);
 67  1
         DTD_RESOURCE_BY_ID.put(DTD_PUBLIC_ID_1_1, DTD_RESOURCE_NAME_1_1);
 68  1
     }
 69  
     /**
 70  
      * Constructs an instance.
 71  
      * @throws ParserConfigurationException if an error occurs.
 72  
      * @throws SAXException if an error occurs.
 73  
      */
 74  
     private ImportControlLoader() throws ParserConfigurationException,
 75  
             SAXException
 76  
     {
 77  7
         super(DTD_RESOURCE_BY_ID);
 78  7
     }
 79  
 
 80  
     @Override
 81  
     public void startElement(final String aNamespaceURI,
 82  
                              final String aLocalName,
 83  
                              final String aQName,
 84  
                              final Attributes aAtts)
 85  
         throws SAXException
 86  
     {
 87  36
         if ("import-control".equals(aQName)) {
 88  6
             final String pkg = safeGet(aAtts, "pkg");
 89  6
             mStack.push(new PkgControl(pkg));
 90  6
         }
 91  30
         else if ("subpackage".equals(aQName)) {
 92  5
             assert !mStack.isEmpty();
 93  5
             final String name = safeGet(aAtts, "name");
 94  5
             mStack.push(new PkgControl(mStack.peek(), name));
 95  5
         }
 96  25
         else if ("allow".equals(aQName) || "disallow".equals(aQName)) {
 97  25
             assert !mStack.isEmpty();
 98  
             // Need to handle either "pkg" or "class" attribute.
 99  
             // May have "exact-match" for "pkg"
 100  
             // May have "local-only"
 101  25
             final boolean isAllow = "allow".equals(aQName);
 102  25
             final boolean isLocalOnly = (aAtts.getValue("local-only") != null);
 103  25
             final String pkg = aAtts.getValue("pkg");
 104  25
             final boolean regex = (aAtts.getValue("regex") != null);
 105  
             final Guard g;
 106  25
             if (pkg != null) {
 107  10
                 final boolean exactMatch =
 108  
                     (aAtts.getValue("exact-match") != null);
 109  10
                 g = new Guard(isAllow, isLocalOnly, pkg, exactMatch, regex);
 110  10
             }
 111  
             else {
 112  
                 // handle class names which can be normal class names or regular
 113  
                 // expressions
 114  15
                 final String clazz = safeGet(aAtts, "class");
 115  15
                 g = new Guard(isAllow, isLocalOnly, clazz, regex);
 116  
             }
 117  
 
 118  25
             final PkgControl pc = mStack.peek();
 119  25
             pc.addGuard(g);
 120  
         }
 121  36
     }
 122  
 
 123  
     @Override
 124  
     public void endElement(final String aNamespaceURI, final String aLocalName,
 125  
         final String aQName)
 126  
     {
 127  36
         if ("subpackage".equals(aQName)) {
 128  5
             assert mStack.size() > 1;
 129  5
             mStack.pop();
 130  
         }
 131  36
     }
 132  
 
 133  
     /**
 134  
      * Loads the import control file from a file.
 135  
      * @param aUri the uri of the file to load.
 136  
      * @return the root {@link PkgControl} object.
 137  
      * @throws CheckstyleException if an error occurs.
 138  
      */
 139  
     static PkgControl load(final URI aUri) throws CheckstyleException
 140  
     {
 141  8
         InputStream is = null;
 142  
         try {
 143  8
             is = aUri.toURL().openStream();
 144  
         }
 145  0
         catch (final MalformedURLException e) {
 146  0
             throw new CheckstyleException("syntax error in url " + aUri, e);
 147  
         }
 148  1
         catch (final IOException e) {
 149  1
             throw new CheckstyleException("unable to find " + aUri, e);
 150  7
         }
 151  7
         final InputSource source = new InputSource(is);
 152  7
         return load(source, aUri);
 153  
     }
 154  
 
 155  
     /**
 156  
      * Loads the import control file from a {@link InputSource}.
 157  
      * @param aSource the source to load from.
 158  
      * @param aUri uri of the source being loaded.
 159  
      * @return the root {@link PkgControl} object.
 160  
      * @throws CheckstyleException if an error occurs.
 161  
      */
 162  
     private static PkgControl load(final InputSource aSource,
 163  
         final URI aUri) throws CheckstyleException
 164  
     {
 165  
         try {
 166  7
             final ImportControlLoader loader = new ImportControlLoader();
 167  7
             loader.parseInputSource(aSource);
 168  6
             return loader.getRoot();
 169  
         }
 170  0
         catch (final ParserConfigurationException e) {
 171  0
             throw new CheckstyleException("unable to parse " + aUri, e);
 172  
         }
 173  1
         catch (final SAXException e) {
 174  1
             throw new CheckstyleException("unable to parse " + aUri
 175  
                     + " - " + e.getMessage(), e);
 176  
         }
 177  0
         catch (final IOException e) {
 178  0
             throw new CheckstyleException("unable to read " + aUri, e);
 179  
         }
 180  
     }
 181  
 
 182  
     /**
 183  
      * @return the root {@link PkgControl} object loaded.
 184  
      */
 185  
     private PkgControl getRoot()
 186  
     {
 187  6
         assert mStack.size() == 1;
 188  6
         return mStack.peek();
 189  
     }
 190  
 
 191  
     /**
 192  
      * Utility to safely get an attribute. If it does not exist an exception
 193  
      * is thrown.
 194  
      * @param aAtts collect to get attribute from.
 195  
      * @param aName name of the attribute to get.
 196  
      * @return the value of the attribute.
 197  
      * @throws SAXException if the attribute does not exist.
 198  
      */
 199  
     private String safeGet(final Attributes aAtts, final String aName)
 200  
         throws SAXException
 201  
     {
 202  26
         final String retVal = aAtts.getValue(aName);
 203  26
         if (retVal == null) {
 204  0
             throw new SAXException("missing attribute " + aName);
 205  
         }
 206  26
         return retVal;
 207  
     }
 208  
 }