Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
JarAnalyzer |
|
| 1.6363636363636365;1.636 | ||||
JarAnalyzer$1 |
|
| 1.6363636363636365;1.636 |
1 | package org.apache.maven.shared.jar; | |
2 | ||
3 | /* | |
4 | * Licensed to the Apache Software Foundation (ASF) under one | |
5 | * or more contributor license agreements. See the NOTICE file | |
6 | * distributed with this work for additional information | |
7 | * regarding copyright ownership. The ASF licenses this file | |
8 | * to you under the Apache License, Version 2.0 (the | |
9 | * "License"); you may not use this file except in compliance | |
10 | * with the License. You may obtain a copy of the License at | |
11 | * | |
12 | * http://www.apache.org/licenses/LICENSE-2.0 | |
13 | * | |
14 | * Unless required by applicable law or agreed to in writing, | |
15 | * software distributed under the License is distributed on an | |
16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
17 | * KIND, either express or implied. See the License for the | |
18 | * specific language governing permissions and limitations | |
19 | * under the License. | |
20 | */ | |
21 | ||
22 | import java.io.File; | |
23 | import java.io.IOException; | |
24 | import java.io.InputStream; | |
25 | import java.util.ArrayList; | |
26 | import java.util.Collections; | |
27 | import java.util.Comparator; | |
28 | import java.util.Iterator; | |
29 | import java.util.List; | |
30 | import java.util.jar.JarEntry; | |
31 | import java.util.jar.JarFile; | |
32 | import java.util.jar.Manifest; | |
33 | import java.util.regex.Matcher; | |
34 | import java.util.regex.Pattern; | |
35 | import java.util.zip.ZipException; | |
36 | ||
37 | /** | |
38 | * Open a JAR file to be analyzed. Note that once created, the {@link #closeQuietly()} method should be called to | |
39 | * release the associated file handle. | |
40 | * <p/> | |
41 | * Typical usage: | |
42 | * <pre> | |
43 | * JarAnalyzer jar = new JarAnalyzer( jarFile ); | |
44 | * <p/> | |
45 | * try | |
46 | * { | |
47 | * // do some analysis, such as: | |
48 | * jarClasses = jarClassAnalyzer.analyze( jar ); | |
49 | * } | |
50 | * finally | |
51 | * { | |
52 | * jar.closeQuietly(); | |
53 | * } | |
54 | * <p/> | |
55 | * // use jar.getJarData() in some way, or the data returned by the JAR analyzer. jar itself can no longer be used. | |
56 | * </pre> | |
57 | * <p/> | |
58 | * Note: that the actual data is separated from this class by design to minimise the chance of forgetting to close the | |
59 | * JAR file. The {@link org.apache.maven.shared.jar.JarData} class exposed, as well as any data returned by actual | |
60 | * analyzers that use this class, can be used safely once this class is out of scope. | |
61 | * | |
62 | * @see org.apache.maven.shared.jar.identification.JarIdentificationAnalysis#analyze(JarAnalyzer) | |
63 | * @see org.apache.maven.shared.jar.classes.JarClassesAnalysis#analyze(JarAnalyzer) | |
64 | */ | |
65 | public class JarAnalyzer | |
66 | { | |
67 | /** | |
68 | * Pattern to filter JAR entries for class files. | |
69 | * | |
70 | * @todo why are inner classes and other potentially valid classes omitted? (It flukes it by finding everything after $) | |
71 | */ | |
72 | 0 | private static final Pattern CLASS_FILTER = Pattern.compile( "[A-Za-z0-9]*\\.class$" ); |
73 | ||
74 | /** | |
75 | * Pattern to filter JAR entries for Maven POM files. | |
76 | */ | |
77 | 0 | private static final Pattern MAVEN_POM_FILTER = Pattern.compile( "META-INF/maven/.*/pom\\.xml$" ); |
78 | ||
79 | /** | |
80 | * Pattern to filter JAR entries for text files that may contain a version. | |
81 | */ | |
82 | 0 | private static final Pattern VERSION_FILTER = Pattern.compile( "[Vv][Ee][Rr][Ss][Ii][Oo][Nn]" ); |
83 | ||
84 | /** | |
85 | * The associated JAR file. | |
86 | */ | |
87 | private final JarFile jarFile; | |
88 | ||
89 | /** | |
90 | * Contains information about the data collected so far. | |
91 | */ | |
92 | private final JarData jarData; | |
93 | ||
94 | /** | |
95 | * Constructor. Opens the JAR file, so should be matched by a call to {@link #closeQuietly()}. | |
96 | * | |
97 | * @param file the JAR file to open | |
98 | * @throws java.io.IOException if there is a problem opening the JAR file, or reading the manifest. The JAR file will be closed if this occurs. | |
99 | */ | |
100 | public JarAnalyzer( File file ) | |
101 | throws IOException | |
102 | 0 | { |
103 | try | |
104 | { | |
105 | 0 | this.jarFile = new JarFile( file ); |
106 | } | |
107 | 0 | catch ( ZipException e ) |
108 | { | |
109 | 0 | ZipException ioe = new ZipException( "Failed to open file " + file + " : " + e.getMessage() ); |
110 | 0 | ioe.initCause( e ); |
111 | 0 | throw ioe; |
112 | 0 | } |
113 | ||
114 | // Obtain entries list. | |
115 | 0 | List entries = Collections.list( jarFile.entries() ); |
116 | ||
117 | // Sorting of list is done by name to ensure a bytecode hash is always consistent. | |
118 | 0 | Collections.sort( entries, new Comparator() |
119 | 0 | { |
120 | public int compare( Object o1, Object o2 ) | |
121 | { | |
122 | 0 | JarEntry entry1 = (JarEntry) o1; |
123 | 0 | JarEntry entry2 = (JarEntry) o2; |
124 | ||
125 | 0 | return entry1.getName().compareTo( entry2.getName() ); |
126 | } | |
127 | } ); | |
128 | ||
129 | Manifest manifest; | |
130 | try | |
131 | { | |
132 | 0 | manifest = jarFile.getManifest(); |
133 | } | |
134 | 0 | catch ( IOException e ) |
135 | { | |
136 | 0 | closeQuietly(); |
137 | 0 | throw e; |
138 | 0 | } |
139 | 0 | this.jarData = new JarData( file, manifest, entries ); |
140 | 0 | } |
141 | ||
142 | /** | |
143 | * Get the data for an individual entry in the JAR. The caller should closeQuietly the input stream, and should not retain | |
144 | * the stream as the JAR file may be closed elsewhere. | |
145 | * | |
146 | * @param entry the JAR entry to read from | |
147 | * @return the input stream of the individual JAR entry. | |
148 | * @throws java.io.IOException if there is a problem opening the individual entry | |
149 | */ | |
150 | public InputStream getEntryInputStream( JarEntry entry ) | |
151 | throws IOException | |
152 | { | |
153 | 0 | return jarFile.getInputStream( entry ); |
154 | } | |
155 | ||
156 | /** | |
157 | * Close the associated JAR file, ignoring any errors that may occur. | |
158 | */ | |
159 | public void closeQuietly() | |
160 | { | |
161 | try | |
162 | { | |
163 | 0 | jarFile.close(); |
164 | } | |
165 | 0 | catch ( IOException e ) |
166 | { | |
167 | // not much we can do about it but ignore it | |
168 | 0 | } |
169 | 0 | } |
170 | ||
171 | /** | |
172 | * Filter a list of JAR entries against the pattern. | |
173 | * | |
174 | * @param pattern the pattern to filter against | |
175 | * @return the list of files found, in {@link java.util.jar.JarEntry} elements | |
176 | */ | |
177 | public List filterEntries( Pattern pattern ) | |
178 | { | |
179 | 0 | List ret = new ArrayList(); |
180 | ||
181 | 0 | Iterator it = getEntries().iterator(); |
182 | 0 | while ( it.hasNext() ) |
183 | { | |
184 | 0 | JarEntry entry = (JarEntry) it.next(); |
185 | ||
186 | 0 | Matcher mat = pattern.matcher( entry.getName() ); |
187 | 0 | if ( mat.find() ) |
188 | { | |
189 | 0 | ret.add( entry ); |
190 | } | |
191 | 0 | } |
192 | 0 | return ret; |
193 | } | |
194 | ||
195 | /** | |
196 | * Get all the classes in the JAR. | |
197 | * | |
198 | * @return the list of files found, in {@link java.util.jar.JarEntry} elements | |
199 | */ | |
200 | public List getClassEntries() | |
201 | { | |
202 | 0 | return filterEntries( CLASS_FILTER ); |
203 | } | |
204 | ||
205 | /** | |
206 | * Get all the Maven POM entries in the JAR. | |
207 | * | |
208 | * @return the list of files found, in {@link java.util.jar.JarEntry} elements | |
209 | */ | |
210 | public List getMavenPomEntries() | |
211 | { | |
212 | 0 | return filterEntries( MAVEN_POM_FILTER ); |
213 | } | |
214 | ||
215 | /** | |
216 | * Get all the version text files in the JAR. | |
217 | * | |
218 | * @return the list of files found, in {@link java.util.jar.JarEntry} elements | |
219 | */ | |
220 | public List getVersionEntries() | |
221 | { | |
222 | 0 | return filterEntries( VERSION_FILTER ); |
223 | } | |
224 | ||
225 | /** | |
226 | * Get all the contained files in the JAR. | |
227 | * | |
228 | * @return the list of files found, in {@link java.util.jar.JarEntry} elements | |
229 | */ | |
230 | public List getEntries() | |
231 | { | |
232 | 0 | return jarData.getEntries(); |
233 | } | |
234 | ||
235 | /** | |
236 | * Get the file that was opened by this analyzer. | |
237 | * | |
238 | * @return the JAR file reference | |
239 | */ | |
240 | public File getFile() | |
241 | { | |
242 | 0 | return jarData.getFile(); |
243 | } | |
244 | ||
245 | public JarData getJarData() | |
246 | { | |
247 | 0 | return jarData; |
248 | } | |
249 | } |