001: ////////////////////////////////////////////////////////////////////////////////
002: // checkstyle: Checks Java source code for adherence to a set of rules.
003: // Copyright (C) 2001-2007 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: ////////////////////////////////////////////////////////////////////////////////
019: package com.puppycrawl.tools.checkstyle.checks.imports;
020:
021: import com.puppycrawl.tools.checkstyle.api.AbstractLoader;
022: import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.net.MalformedURLException;
026: import java.net.URI;
027: import java.util.Stack;
028: import javax.xml.parsers.ParserConfigurationException;
029: import org.xml.sax.Attributes;
030: import org.xml.sax.InputSource;
031: import org.xml.sax.SAXException;
032:
033: /**
034: * Responsible for loading the contents of an import control configuration file.
035: * @author Oliver Burn
036: */
037: final class ImportControlLoader extends AbstractLoader {
038: /** the public ID for the configuration dtd */
039: private static final String DTD_PUBLIC_ID = "-//Puppy Crawl//DTD Import Control 1.0//EN";
040:
041: /** the resource for the configuration dtd */
042: private static final String DTD_RESOURCE_NAME = "com/puppycrawl/tools/checkstyle/checks/imports/import_control_1_0.dtd";
043:
044: /** Used to hold the {@link PkgControl} objects. */
045: private final Stack mStack = new Stack();
046:
047: /**
048: * Constructs an instance.
049: * @throws ParserConfigurationException if an error occurs.
050: * @throws SAXException if an error occurs.
051: */
052: private ImportControlLoader() throws ParserConfigurationException,
053: SAXException {
054: super (DTD_PUBLIC_ID, DTD_RESOURCE_NAME);
055: }
056:
057: /** {@inheritDoc} */
058: public void startElement(final String aNamespaceURI,
059: final String aLocalName, final String aQName,
060: final Attributes aAtts) throws SAXException {
061: if (aQName.equals("import-control")) {
062: final String pkg = safeGet(aAtts, "pkg");
063: mStack.push(new PkgControl(pkg));
064: } else if (aQName.equals("subpackage")) {
065: assert mStack.size() > 0;
066: final String name = safeGet(aAtts, "name");
067: mStack
068: .push(new PkgControl((PkgControl) mStack.peek(),
069: name));
070: } else if (aQName.equals("allow") || aQName.equals("disallow")) {
071: assert mStack.size() > 0;
072: // Need to handle either "pkg" or "class" attribute.
073: // May have "exact-match" for "pkg"
074: // May have "local-only"
075: final boolean isAllow = aQName.equals("allow");
076: final boolean isLocalOnly = (aAtts.getValue("local-only") != null);
077: final String pkg = aAtts.getValue("pkg");
078: final Guard g;
079: if (pkg != null) {
080: final boolean exactMatch = (aAtts
081: .getValue("exact-match") != null);
082: g = new Guard(isAllow, isLocalOnly, pkg, exactMatch);
083: } else {
084: final String clazz = safeGet(aAtts, "class");
085: g = new Guard(isAllow, isLocalOnly, clazz);
086: }
087:
088: final PkgControl pc = (PkgControl) mStack.peek();
089: pc.addGuard(g);
090: }
091: }
092:
093: /** {@inheritDoc} */
094: public void endElement(final String aNamespaceURI,
095: final String aLocalName, final String aQName) {
096: if (aQName.equals("subpackage")) {
097: assert mStack.size() > 1;
098: mStack.pop();
099: }
100: }
101:
102: /**
103: * Loads the import control file from a file.
104: * @param aUri the uri of the file to load.
105: * @return the root {@link PkgControl} object.
106: * @throws CheckstyleException if an error occurs.
107: */
108: static PkgControl load(final URI aUri) throws CheckstyleException {
109: InputStream is = null;
110: try {
111: is = aUri.toURL().openStream();
112: } catch (final MalformedURLException e) {
113: throw new CheckstyleException(
114: "syntax error in url " + aUri, e);
115: } catch (final IOException e) {
116: throw new CheckstyleException("unable to find " + aUri, e);
117: }
118: final InputSource source = new InputSource(is);
119: return load(source, aUri);
120: }
121:
122: /**
123: * Loads the import control file from a {@link InputSource}.
124: * @param aSource the source to load from.
125: * @param aUri uri of the source being loaded.
126: * @return the root {@link PkgControl} object.
127: * @throws CheckstyleException if an error occurs.
128: */
129: private static PkgControl load(final InputSource aSource,
130: final URI aUri) throws CheckstyleException {
131: try {
132: final ImportControlLoader loader = new ImportControlLoader();
133: loader.parseInputSource(aSource);
134: return loader.getRoot();
135: } catch (final ParserConfigurationException e) {
136: throw new CheckstyleException("unable to parse " + aUri, e);
137: } catch (final SAXException e) {
138: throw new CheckstyleException("unable to parse " + aUri
139: + " - " + e.getMessage(), e);
140: } catch (final IOException e) {
141: throw new CheckstyleException("unable to read " + aUri, e);
142: }
143: }
144:
145: /**
146: * @return the root {@link PkgControl} object loaded.
147: */
148: private PkgControl getRoot() {
149: assert mStack.size() == 1;
150: return (PkgControl) mStack.peek();
151: }
152:
153: /**
154: * Utility to safely get an attribute. If it does not exist an exception
155: * is thrown.
156: * @param aAtts collect to get attribute from.
157: * @param aName name of the attribute to get.
158: * @return the value of the attribute.
159: * @throws SAXException if the attribute does not exist.
160: */
161: private String safeGet(final Attributes aAtts, final String aName)
162: throws SAXException {
163: final String retVal = aAtts.getValue(aName);
164: if (retVal == null) {
165: throw new SAXException("missing attibute " + aName);
166: }
167: return retVal;
168: }
169: }
|