Skip to content

Commit 0a1b443

Browse files
committed
ClassUtil: inspect all jar files in search of all class names,
and collect info and URLs from their pom.xml
1 parent 7507734 commit 0a1b443

File tree

1 file changed

+233
-0
lines changed

1 file changed

+233
-0
lines changed
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
package org.scijava.ui.swing.script;
2+
3+
import java.io.File;
4+
import java.io.IOException;
5+
import java.net.URL;
6+
import java.net.URLConnection;
7+
import java.util.ArrayList;
8+
import java.util.Enumeration;
9+
import java.util.HashMap;
10+
import java.util.HashSet;
11+
import java.util.LinkedList;
12+
import java.util.Map;
13+
import java.util.Scanner;
14+
import java.util.jar.JarEntry;
15+
import java.util.jar.JarFile;
16+
import java.util.regex.Matcher;
17+
import java.util.regex.Pattern;
18+
19+
public class ClassUtil {
20+
21+
static private final String scijava_javadoc_URL = "https://javadoc.scijava.org/"; // with ending slash
22+
23+
/** Cache of class names vs list of URLs found in the pom.xml files of their contaning jar files, if any. */
24+
static private final Map<String, JarProperties> class_urls = new HashMap<>();
25+
26+
/** Cache of subURL javadoc at https://javadoc.scijava.org */
27+
static private final HashMap<String, String> scijava_javadoc_URLs = new HashMap<>();
28+
29+
static private final void ensureCache() {
30+
synchronized (class_urls) {
31+
if (class_urls.isEmpty())
32+
class_urls.putAll(findAllClasses());
33+
}
34+
}
35+
36+
static public final void ensureSciJavaSubURLCache() {
37+
synchronized (scijava_javadoc_URLs) {
38+
if (!scijava_javadoc_URLs.isEmpty()) return;
39+
Scanner scanner = null;
40+
try {
41+
final Pattern pattern = Pattern.compile("<div class=\"jdbox\"><div><a href=\"(.*?)\">");
42+
final URLConnection connection = new URL(scijava_javadoc_URL).openConnection();
43+
scanner = new Scanner(connection.getInputStream());
44+
while (scanner.hasNext()) {
45+
final Matcher matcher = pattern.matcher(scanner.nextLine());
46+
if (matcher.find()) {
47+
String name = matcher.group(1).toLowerCase();
48+
if (name.endsWith("/")) name = name.substring(0, name.length() -1);
49+
scijava_javadoc_URLs.put(name, scijava_javadoc_URL + matcher.group(1));
50+
}
51+
}
52+
scanner.close();
53+
} catch ( Exception e ) {
54+
e.printStackTrace();
55+
} finally {
56+
if (null != scanner) scanner.close();
57+
}
58+
}
59+
}
60+
61+
static public HashMap<String, JarProperties> findClassDocumentationURLs(final String s) {
62+
ensureCache();
63+
final HashMap<String, JarProperties> matches = new HashMap<>();
64+
for (final Map.Entry<String, JarProperties> entry: class_urls.entrySet()) {
65+
if (entry.getKey().contains(s)) {
66+
final JarProperties props = entry.getValue();
67+
matches.put(entry.getKey(), new JarProperties(props.name, new ArrayList<String>(props.urls)));
68+
}
69+
}
70+
return matches;
71+
}
72+
73+
static public HashMap<String, ArrayList<String>> findDocumentationForClass(final String s) {
74+
final HashMap<String, JarProperties> matches = findClassDocumentationURLs(s);
75+
ensureSciJavaSubURLCache();
76+
77+
final Pattern java8 = Pattern.compile("^(java|javax|org.omg|org.w3c|org.xml|org.ietf.jgss)\\..*$");
78+
79+
final HashMap<String, ArrayList<String>> class_urls = new HashMap<>();
80+
81+
for (final Map.Entry<String, JarProperties> entry: matches.entrySet()) {
82+
final String classname = entry.getKey();
83+
final ArrayList<String> urls = new ArrayList<>();
84+
class_urls.put(classname, urls);
85+
if (java8.matcher(classname).matches()) {
86+
urls.add(scijava_javadoc_URLs.get("java8") + classname.replace('.', '/') + ".html");
87+
} else {
88+
final JarProperties props = entry.getValue();
89+
// Find the first URL with git in it
90+
for (final String url : props.urls) {
91+
final boolean github = url.contains("/github.com"),
92+
gitlab = url.contains("/gitlab.com");
93+
if (github || gitlab) {
94+
// Find the 5th slash, e.g. https://github.com/imglib/imglib2/
95+
int count = 0;
96+
int last = 0;
97+
while (count < 5) {
98+
last = url.indexOf('/', last + 1);
99+
if (-1 == last) break; // less than 5 found
100+
++count;
101+
}
102+
String urlbase = url;
103+
if (5 == count) urlbase = url.substring(0, last); // without the ending slash
104+
// Assume maven, since these URLs were found in a pom.xml: src/main/java/
105+
urls.add(urlbase + (gitlab ? "/-" : "") + "/blob/master/src/main/java/" + classname.replace('.', '/') + ".java");
106+
break;
107+
}
108+
}
109+
// Try to find a javadoc in the scijava website
110+
if (null != props.name) {
111+
String scijava_javadoc_url = scijava_javadoc_URLs.get(props.name.toLowerCase());
112+
if (null == scijava_javadoc_url) {
113+
// Try cropping name at the first whitespace if any (e.g. "ImgLib2 Core Library" to "ImgLib2")
114+
final int ispace = props.name.indexOf(' ');
115+
if (-1 != ispace) {
116+
scijava_javadoc_url = scijava_javadoc_URLs.get(props.name.toLowerCase().substring(0, ispace));
117+
}
118+
}
119+
if (null != scijava_javadoc_url) {
120+
urls.add(scijava_javadoc_url + classname.replace('.', '/') + ".html");
121+
} else {
122+
// Try Fiji: could be a plugin
123+
Scanner scanner = null;
124+
try {
125+
final String url = scijava_javadoc_URL + "Fiji/" + classname.replace('.', '/') + ".html";
126+
final URLConnection c = new URL(url).openConnection();
127+
scanner = new Scanner(c.getInputStream());
128+
while (scanner.hasNext()) {
129+
final String line = scanner.nextLine();
130+
if (line.contains("<title>")) {
131+
if (!line.contains("<title>404")) {
132+
urls.add(url);
133+
}
134+
break;
135+
}
136+
}
137+
} catch (Exception e) {
138+
// Ignore: 404 that wasn't redirected to an error page
139+
} finally {
140+
if (null != scanner) scanner.close();
141+
}
142+
}
143+
}
144+
}
145+
}
146+
147+
return class_urls;
148+
}
149+
150+
static public final class JarProperties {
151+
public final ArrayList<String> urls;
152+
public String name = null;
153+
public JarProperties(final String name, final ArrayList<String> urls) {
154+
this.name = name;
155+
this.urls = urls;
156+
}
157+
}
158+
159+
static public final HashMap<String, JarProperties> findAllClasses() {
160+
// Find all jar files
161+
final ArrayList<String> jarFilePaths = new ArrayList<String>();
162+
final LinkedList<String> dirs = new LinkedList<>();
163+
dirs.add(System.getProperty("java.home"));
164+
dirs.add(System.getProperty("ij.dir"));
165+
final HashSet<String> seenDirs = new HashSet<>();
166+
while (!dirs.isEmpty()) {
167+
final String filepath = dirs.removeFirst();
168+
final File file = new File(filepath);
169+
seenDirs.add(file.getAbsolutePath());
170+
if (file.exists()) {
171+
if (file.isDirectory()) {
172+
for (final File child : file.listFiles()) {
173+
final String childfilepath = child.getAbsolutePath();
174+
if (seenDirs.contains(childfilepath)) continue;
175+
if (child.isDirectory()) dirs.add(childfilepath);
176+
else if (childfilepath.endsWith(".jar")) jarFilePaths.add(childfilepath);
177+
}
178+
}
179+
}
180+
}
181+
// Find all classes from all jar files
182+
final HashMap<String, JarProperties> class_urls = new HashMap<>();
183+
final Pattern urlpattern = Pattern.compile(">(http.*?)<");
184+
final Pattern namepattern = Pattern.compile("<name>(.*?)<");
185+
for (final String jarpath : jarFilePaths) {
186+
JarFile jar = null;
187+
try {
188+
jar = new JarFile(jarpath);
189+
final Enumeration<JarEntry> entries = jar.entries();
190+
final ArrayList<String> urls = new ArrayList<>();
191+
final JarProperties props = new JarProperties(null, urls);
192+
// For every filepath in the jar zip archive
193+
while (entries.hasMoreElements()) {
194+
final JarEntry entry = entries.nextElement();
195+
if (entry.isDirectory()) continue;
196+
if (entry.getName().endsWith(".class")) {
197+
String classname = entry.getName().replace('/', '.');
198+
final int idollar = classname.indexOf('$');
199+
if (-1 != idollar) {
200+
classname = classname.substring(0, idollar); // truncate at the first dollar sign
201+
} else {
202+
classname = classname.substring(0, classname.length() - 6); // without .class
203+
}
204+
class_urls.put(classname, props);
205+
} else if (entry.getName().endsWith("/pom.xml")) {
206+
final Scanner scanner = new Scanner(jar.getInputStream(entry));
207+
while (scanner.hasNext()) {
208+
final String line = scanner.nextLine();
209+
final Matcher matcher1 = urlpattern.matcher(line);
210+
if (matcher1.find()) {
211+
urls.add(matcher1.group(1));
212+
}
213+
if (null == props.name) {
214+
final Matcher matcher2 = namepattern.matcher(line);
215+
if (matcher2.find()) {
216+
props.name = matcher2.group(1);
217+
}
218+
}
219+
}
220+
scanner.close();
221+
}
222+
}
223+
} catch (IOException e) {
224+
e.printStackTrace();
225+
} finally {
226+
if (null != jar) try {
227+
jar.close();
228+
} catch (IOException e) { e.printStackTrace(); }
229+
}
230+
}
231+
return class_urls;
232+
}
233+
}

0 commit comments

Comments
 (0)