1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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.Collections;
28 import java.util.Deque;
29 import java.util.Enumeration;
30 import java.util.HashMap;
31 import java.util.Iterator;
32 import java.util.LinkedHashSet;
33 import java.util.Map;
34 import java.util.Set;
35
36 import javax.xml.parsers.ParserConfigurationException;
37
38 import org.xml.sax.Attributes;
39 import org.xml.sax.InputSource;
40 import org.xml.sax.SAXException;
41
42 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
43
44
45
46
47 public final class PackageNamesLoader
48 extends XmlLoader {
49
50
51 private static final String DTD_PUBLIC_ID =
52 "-//Puppy Crawl//DTD Package Names 1.0//EN";
53
54
55 private static final String DTD_PUBLIC_CS_ID =
56 "-//Checkstyle//DTD Package Names Configuration 1.0//EN";
57
58
59 private static final String DTD_RESOURCE_NAME =
60 "com/puppycrawl/tools/checkstyle/packages_1_0.dtd";
61
62
63
64
65
66 private static final String CHECKSTYLE_PACKAGES =
67 "checkstyle_packages.xml";
68
69
70 private static final String PACKAGE_ELEMENT_NAME = "package";
71
72
73 private final Deque<String> packageStack = new ArrayDeque<>();
74
75
76 private final Set<String> packageNames = new LinkedHashSet<>();
77
78
79
80
81
82
83
84 private PackageNamesLoader()
85 throws ParserConfigurationException, SAXException {
86 super(createIdToResourceNameMap());
87 }
88
89 @Override
90 public void startElement(String uri,
91 String localName,
92 String qName,
93 Attributes attributes) {
94 if (PACKAGE_ELEMENT_NAME.equals(qName)) {
95
96 final String name = attributes.getValue("name");
97 packageStack.push(name);
98 }
99 }
100
101
102
103
104
105
106 private String getPackageName() {
107 final StringBuilder buf = new StringBuilder(256);
108 final Iterator<String> iterator = packageStack.descendingIterator();
109 while (iterator.hasNext()) {
110 final String subPackage = iterator.next();
111 buf.append(subPackage);
112 if (!subPackage.endsWith(".") && iterator.hasNext()) {
113 buf.append('.');
114 }
115 }
116 return buf.toString();
117 }
118
119 @Override
120 public void endElement(String uri,
121 String localName,
122 String qName) {
123 if (PACKAGE_ELEMENT_NAME.equals(qName)) {
124 packageNames.add(getPackageName());
125 packageStack.pop();
126 }
127 }
128
129
130
131
132
133
134
135
136
137
138
139 public static Set<String> getPackageNames(ClassLoader classLoader)
140 throws CheckstyleException {
141 final Set<String> result;
142 try {
143
144
145 final PackageNamesLoader namesLoader = new PackageNamesLoader();
146
147 final Enumeration<URL> packageFiles = classLoader.getResources(CHECKSTYLE_PACKAGES);
148
149 while (packageFiles.hasMoreElements()) {
150 processFile(packageFiles.nextElement(), namesLoader);
151 }
152
153 result = namesLoader.packageNames;
154 }
155 catch (IOException ex) {
156 throw new CheckstyleException("unable to get package file resources", ex);
157 }
158 catch (ParserConfigurationException | SAXException ex) {
159 throw new CheckstyleException("unable to open one of package files", ex);
160 }
161
162 return Collections.unmodifiableSet(result);
163 }
164
165
166
167
168
169
170
171
172
173 private static void processFile(URL packageFile, PackageNamesLoader namesLoader)
174 throws SAXException, CheckstyleException {
175 try (InputStream stream = new BufferedInputStream(packageFile.openStream())) {
176 final InputSource source = new InputSource(stream);
177 namesLoader.parseInputSource(source);
178 }
179 catch (IOException ex) {
180 throw new CheckstyleException("unable to open " + packageFile, ex);
181 }
182 }
183
184
185
186
187
188
189 private static Map<String, String> createIdToResourceNameMap() {
190 final Map<String, String> map = new HashMap<>();
191 map.put(DTD_PUBLIC_ID, DTD_RESOURCE_NAME);
192 map.put(DTD_PUBLIC_CS_ID, DTD_RESOURCE_NAME);
193 return map;
194 }
195
196 }