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