Skip to content

Commit 98169ca

Browse files
committedJun 8, 2024
[>] Display results
1 parent 97d2d46 commit 98169ca

File tree

7 files changed

+199
-45
lines changed

7 files changed

+199
-45
lines changed
 

‎README.md

+25-41
Original file line numberDiff line numberDiff line change
@@ -4,51 +4,35 @@ A repository for my live-coding talk [Modern Java in Action](https://nipafx.dev/
44

55
## Next
66

7-
Records:
8-
* create `record PageWithLinks(Page page, Set<URI> links)`
9-
* additional constructor without `links`
7+
This is where string templates used to come in.
8+
Since [they're out](https://bugs.openjdk.org/browse/JDK-8329948) in JDK 23, there's nothing to do here except boring string formatting and method calls:
9+
* change output in `GitHubCrawl::main` to:
10+
```java
11+
System.out.printf("""
1012

11-
Modules:
12-
* fix errors in `PageFactory`: `requires org.jsoup;`
13-
* fix errors in `PageTreeFactory`: `requires java.net.http;`
13+
---
1414

15-
HTTP client:
16-
* instantiate `HttpClient` in `GitHubCrawl`:
17-
```java
18-
var client = HttpClient.newHttpClient();
15+
%s
16+
%s
17+
18+
19+
""", Statistician.evaluate(rootPage), Pretty.pageList(rootPage));
1920
```
20-
* `PageTreeFactory::fetchPageAsString`:
21+
* parse to HTML in `ResultServer::serve`:
2122
```java
22-
var request = HttpRequest
23-
.newBuilder(url)
24-
.GET()
25-
.build();
26-
return client
27-
.send(request, BodyHandlers.ofString())
28-
.body();
23+
var html = Jsoup.parse("""...""");
2924
```
30-
31-
Structured Concurrency:
32-
* `PageTreeFactory::resolveLinks`:
25+
and update call to `Files.writeString` on next line
26+
* add info in `ResultServer::pageHtml`:
3327
```java
34-
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
35-
var futurePages = new ArrayList<Subtask<Page>>();
36-
for (URI link : links)
37-
futurePages.add(scope.fork(() -> createPage(link, depth)));
38-
39-
scope.join();
40-
scope.throwIfFailed();
41-
42-
return futurePages.stream()
43-
.map(Subtask::get)
44-
.collect(toSet());
45-
} catch (ExecutionException ex) {
46-
// this should not happen as `ErrorPage` instances should have been created for all errors
47-
throw new IllegalStateException("Error cases should have been handled during page creation!", ex);
48-
}
28+
return join(RAW."""
29+
<div class="page level-%d">
30+
<a href="%s">%s</a>
31+
%s
32+
</div>
33+
""".formatted(
34+
level,
35+
page.url().toString(),
36+
Pretty.pageName(page),
37+
reference ? "<span class=\"ref\"></span>" : "");
4938
```
50-
51-
Run:
52-
* add breakpoint for issue #740
53-
* run with arguments `https://github.com/junit-pioneer/junit-pioneer/issues/624 10`
54-
* create and show thread dump

‎serve/style.css

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
body {
2+
background-color: #262429;
3+
color: white;
4+
font-size: 24px;
5+
}
6+
7+
.container {
8+
width: 600px;
9+
margin: 2em auto;
10+
}
11+
12+
.page {
13+
margin: 1em 0;
14+
padding: 0.5em;
15+
border: 1px solid #69ea7d;
16+
border-radius: 0.25em;
17+
18+
display: grid;
19+
grid-template-columns: 1fr auto;
20+
}
21+
22+
.page .ref:before {
23+
content: "⤴";
24+
}
25+
26+
.page.level-1 {
27+
margin-left: 1em;
28+
}
29+
30+
.page.level-2 {
31+
margin-left: 2em;
32+
}
33+
34+
.page.level-3 {
35+
margin-left: 3em;
36+
}
37+
38+
.page.level-4 {
39+
margin-left: 4em;
40+
}
41+
42+
.page.level-5 {
43+
margin-left: 5em;
44+
}
45+
46+
a, a:visited {
47+
color: white;
48+
text-decoration: none;
49+
}

‎src/main/java/dev/nipafx/demo/modern/GitHubCrawl.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
import dev.nipafx.demo.modern.crawler.PageTreeFactory;
44
import dev.nipafx.demo.modern.operations.Pretty;
5+
import dev.nipafx.demo.modern.operations.ResultServer;
56
import dev.nipafx.demo.modern.operations.Statistician;
67

78
import java.net.URI;
89
import java.net.URISyntaxException;
910
import java.net.http.HttpClient;
11+
import java.nio.file.Path;
1012

1113
public class GitHubCrawl {
1214

@@ -20,13 +22,15 @@ public static void main(String[] args) throws Exception {
2022
System.out.printf("%nTo see virtual threads in action, run this while the app is resolving a bunch of links:%n");
2123
System.out.printf("jcmd %s Thread.dump_to_file -format=json -overwrite threads.json%n%n", ProcessHandle.current().pid());
2224

23-
// TODO
24-
var client = (HttpClient) null;
25+
var client = HttpClient.newHttpClient();
2526
var factory = new PageTreeFactory(client);
2627
var rootPage = factory.createPage(config.seedUrl(), config.depth());
2728

29+
// TODO: improve formatting
2830
System.out.println(Statistician.evaluate(rootPage));
2931
System.out.println(Pretty.pageList(rootPage));
32+
33+
ResultServer.serve(rootPage, Path.of("serve"));
3034
}
3135

3236
private record Configuration(URI seedUrl, int depth) {

‎src/main/java/dev/nipafx/demo/modern/crawler/PageTreeFactory.java

+22-2
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,34 @@ private PageWithLinks fetchPageWithLinks(URI url) throws InterruptedException {
6666
}
6767

6868
private String fetchPageAsString(URI url) throws IOException, InterruptedException {
69-
// TODO: create and send HTTP request
69+
var request = HttpRequest
70+
.newBuilder(url)
71+
.GET()
72+
.build();
73+
return client
74+
.send(request, BodyHandlers.ofString())
75+
.body();
7076
}
7177

7278
private Set<Page> resolveLinks(Set<URI> links, int depth) throws InterruptedException {
7379
if (depth < 0)
7480
return Collections.emptySet();
7581

76-
// TODO: resolve links in StructuredTaskScope
82+
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
83+
var futurePages = new ArrayList<Subtask<Page>>();
84+
for (URI link : links)
85+
futurePages.add(scope.fork(() -> createPage(link, depth)));
86+
87+
scope.join();
88+
scope.throwIfFailed();
89+
90+
return futurePages.stream()
91+
.map(Subtask::get)
92+
.collect(toSet());
93+
} catch (ExecutionException ex) {
94+
// this should not happen as `ErrorPage` instances should have been created for all errors
95+
throw new IllegalStateException("Error cases should have been handled during page creation!", ex);
96+
}
7797
}
7898

7999
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package dev.nipafx.demo.modern.crawler;
2+
3+
import dev.nipafx.demo.modern.page.Page;
4+
5+
import java.net.URI;
6+
import java.util.Set;
7+
8+
import static java.util.Objects.requireNonNull;
9+
10+
record PageWithLinks(Page page, Set<URI> links) {
11+
12+
PageWithLinks {
13+
requireNonNull(page);
14+
requireNonNull(links);
15+
links = Set.copyOf(links);
16+
}
17+
18+
public PageWithLinks(Page page) {
19+
this(page, Set.of());
20+
}
21+
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package dev.nipafx.demo.modern.operations;
2+
3+
import dev.nipafx.demo.modern.page.GitHubPage;
4+
import dev.nipafx.demo.modern.page.Page;
5+
6+
import java.io.IOException;
7+
import java.nio.file.Files;
8+
import java.nio.file.Path;
9+
import java.util.HashSet;
10+
import java.util.Set;
11+
12+
import static java.util.stream.Collectors.joining;
13+
14+
public class ResultServer {
15+
16+
public static void serve(Page rootPage, Path serverDir) throws IOException {
17+
if (!Files.exists(serverDir))
18+
Files.createDirectory(serverDir);
19+
20+
// TODO: parse to HTML document
21+
var html = """
22+
<!DOCTYPE html>
23+
<html lang="en">
24+
<head>
25+
<meta charset="utf-8">
26+
<title>%s</title>
27+
<link rel="stylesheet" href="style.css">
28+
</head>
29+
<body>
30+
<div class="container">
31+
%s
32+
</div>
33+
</body>
34+
</html>
35+
""".formatted(Pretty.pageName(rootPage), pageTreeHtml(rootPage));
36+
Files.writeString(serverDir.resolve("index.html"), html);
37+
}
38+
39+
private static String pageTreeHtml(Page rootPage) {
40+
var printedPages = new HashSet<Page>();
41+
return appendPageTreeHtml(printedPages, rootPage, 0);
42+
}
43+
44+
private static String appendPageTreeHtml(Set<Page> printedPages, Page page, int level) {
45+
var pageHtml = pageHtml(page, printedPages.contains(page), level);
46+
if (printedPages.contains(page)) {
47+
printedPages.add(page);
48+
return pageHtml;
49+
} else {
50+
printedPages.add(page);
51+
var descendantsHtml = page instanceof GitHubPage ghPage
52+
? ghPage
53+
.links().stream()
54+
.map(linkedPage -> appendPageTreeHtml(printedPages, linkedPage, level + 1))
55+
.collect(joining("\n"))
56+
: "";
57+
return """
58+
%s
59+
%s
60+
""".formatted(pageHtml, descendantsHtml);
61+
}
62+
}
63+
64+
private static String pageHtml(Page page, boolean reference, int level) {
65+
// TODO: add page info
66+
return """
67+
<div class="page level-0">
68+
<a href=""></a>
69+
</div>
70+
""";
71+
}
72+
73+
}

‎src/main/java/module-info.java

+2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
module gh.crawler {
2+
requires java.net.http;
3+
requires org.jsoup;
24
}

0 commit comments

Comments
 (0)
Please sign in to comment.