Skip to content

Commit

Permalink
Added javadoc to internal report viewer and moved the resource declar…
Browse files Browse the repository at this point in the history
…ation in the pom xml into the profile.
  • Loading branch information
TwoOfTwelve committed Dec 1, 2023
1 parent daede42 commit 71d094c
Show file tree
Hide file tree
Showing 14 changed files with 162 additions and 14 deletions.
12 changes: 6 additions & 6 deletions cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,6 @@
</dependency>
</dependencies>
<build>
<resources>
<resource>
<targetPath>report-viewer</targetPath>
<directory>../report-viewer/dist</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
Expand Down Expand Up @@ -177,6 +171,12 @@
<activeByDefault>true</activeByDefault>
</activation>
<build>
<resources>
<resource>
<targetPath>report-viewer</targetPath>
<directory>../report-viewer/dist</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
Expand Down
12 changes: 12 additions & 0 deletions cli/src/main/java/de/jplag/cli/JPlagMode.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
package de.jplag.cli;

/**
* The mode Jplag runs in. This influences which steps JPlag will execute
*/
public enum JPlagMode {
/**
* Only run jplag and create a results.zip
*/
RUN,
/**
* Only start the report viewer
*/
VIEWER,
/**
* Run JPlag and open the result in report viewer
*/
RUN_AND_VIEW
}
8 changes: 8 additions & 0 deletions cli/src/main/java/de/jplag/cli/server/ContentType.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package de.jplag.cli.server;

/**
* The type of data
*/
public enum ContentType {
HTML("text/html; charset=utf-8"),
JS("application/javascript; charset=utf-8"),
Expand All @@ -18,6 +21,11 @@ public String getValue() {
return value;
}

/**
* Guesses the type from the given path using the suffix after the last '.'.
* @param path The path to guess from
* @return The guessed type
*/
public static ContentType fromPath(String path) {
return switch (path.substring(path.lastIndexOf('.'))) {
case ".html" -> ContentType.HTML;
Expand Down
3 changes: 3 additions & 0 deletions cli/src/main/java/de/jplag/cli/server/HttpMethod.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package de.jplag.cli.server;

/**
* Available http methods
*/
public enum HttpMethod {
GET("GET"),
POST("POST");
Expand Down
23 changes: 22 additions & 1 deletion cli/src/main/java/de/jplag/cli/server/ReportViewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

/**
* Manages the internal report viewer. Serves the static files for the report viewer and the results.zip.
*/
public class ReportViewer implements HttpHandler {
private static final Logger logger = LoggerFactory.getLogger(ReportViewer.class);
private static final int SUCCESS_RESPONSE = 200;
Expand All @@ -24,13 +27,22 @@ public class ReportViewer implements HttpHandler {

private HttpServer server;

/**
* @param zipFile The zip file to use for the report viewer
* @throws IOException If the zip file cannot be read
*/
public ReportViewer(File zipFile) throws IOException {
this.routingTree = new RoutingTree();

this.routingTree.insertRouting("", new RoutingResources("report-viewer").or(new RoutingAlias("index.html")));
this.routingTree.insertRouting("results.zip", new RoutingStaticFile(zipFile, ContentType.ZIP));
}

/**
* Starts the server
* @return The port the server runs at
* @throws IOException If the server cannot be started
*/
public int start() throws IOException {
if (server != null) {
throw new IllegalStateException("Server already started");
Expand All @@ -43,10 +55,18 @@ public int start() throws IOException {
return server.getAddress().getPort();
}

/**
* Stops the server
*/
public void stop() {
server.stop(0);
}

/**
* Do not call manually. Called by the running web server.
* @param exchange The http reqest
* @throws IOException If the IO handling goes wrong
*/
public void handle(HttpExchange exchange) throws IOException {
RoutingPath path = new RoutingPath(exchange.getRequestURI().getPath());
Pair<RoutingPath, Routing> resolved = this.routingTree.resolveRouting(path);
Expand All @@ -62,6 +82,7 @@ public void handle(HttpExchange exchange) throws IOException {

ResponseData responseData = resolved.getRight().fetchData(resolved.getLeft(), exchange, this);
if (responseData == null) {
logger.warn("No response data found for path: " + path.asPath());
exchange.sendResponseHeaders(NOT_FOUND_RESPONSE, 0);
exchange.close();
return;
Expand All @@ -80,7 +101,7 @@ public void handle(HttpExchange exchange) throws IOException {
inputStream.close();
}

public RoutingTree getRoutingTree() {
RoutingTree getRoutingTree() {
return routingTree;
}
}
27 changes: 20 additions & 7 deletions cli/src/main/java/de/jplag/cli/server/ResponseData.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
package de.jplag.cli.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

/**
* Data for a http response
* @param stream The stream containing the binary data
* @param contentType The type of data
* @param size The total size of the data
*/
public record ResponseData(InputStream stream, ContentType contentType, int size) {
/**
* Constructor with unknown type and size. Type will be set to PLAIN.
* @param data The binary data to respond with
*/
public ResponseData(InputStream data) {
this(data, ContentType.PLAIN, 0);
}

/**
* Constructor with unknown size
* @param data The binary data
* @param contentType The type of content
*/
public ResponseData(InputStream data, ContentType contentType) {
this(data, contentType, 0);
}

public ResponseData(File file) throws FileNotFoundException {
this(new FileInputStream(file), ContentType.fromPath(file.getName()), 0);
}

/**
* Creates a new instance for a given resource url.
* @param url The resource url
* @return The new response data
*/
public static ResponseData fromResourceUrl(String url) {
if (url.endsWith("/")) {
return null;
Expand Down
18 changes: 18 additions & 0 deletions cli/src/main/java/de/jplag/cli/server/Routing.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,31 @@

import com.sun.net.httpserver.HttpExchange;

/**
* Handles the data for a url prefix.
*/
public interface Routing {
/**
* @return The methods, that this routing can be used for.
*/
default HttpMethod[] allowedMethods() {
return new HttpMethod[] {HttpMethod.GET};
}

/**
* Gets the data for the given url
* @param subPath The remaining suffix of the url, that is not jet interpreted
* @param request The original http request
* @param viewer The current report viewer
* @return The data to respond with
*/
ResponseData fetchData(RoutingPath subPath, HttpExchange request, ReportViewer viewer);

/**
* Use the other routing if this routing does not find any data.
* @param other The other routing
* @return The combined routing
*/
default Routing or(Routing other) {
return new RoutingFallback(this, other);
}
Expand Down
9 changes: 9 additions & 0 deletions cli/src/main/java/de/jplag/cli/server/RoutingAlias.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@

import com.sun.net.httpserver.HttpExchange;

/**
* An alias routing, that will respond with the response for a different path
*/
public class RoutingAlias implements Routing {
private final RoutingPath path;

/**
* @param path The path to actually use
*/
public RoutingAlias(RoutingPath path) {
this.path = path;
}

/**
* @param path The path to actually use
*/
public RoutingAlias(String path) {
this(new RoutingPath(path));
}
Expand Down
7 changes: 7 additions & 0 deletions cli/src/main/java/de/jplag/cli/server/RoutingFallback.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@

import com.sun.net.httpserver.HttpExchange;

/**
* Responds with the first given routing, unless that would respond with null, in that case the second one is used.
*/
public class RoutingFallback implements Routing {
private final Routing first;
private final Routing second;

/**
* @param first The first routing
* @param second The second routing
*/
public RoutingFallback(Routing first, Routing second) {
this.first = first;
this.second = second;
Expand Down
21 changes: 21 additions & 0 deletions cli/src/main/java/de/jplag/cli/server/RoutingPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@

import java.util.Arrays;

/**
* A path used for routing. Can be used like a linked list.
*/
public class RoutingPath {
private final String[] components;
private final int offset;

/**
* @param path The full path
*/
public RoutingPath(String path) {
this.components = Arrays.stream(path.split("/", 0)).filter(it -> !it.isBlank()).toArray(String[]::new);
this.offset = 0;
Expand All @@ -16,10 +22,16 @@ private RoutingPath(String[] components, int offset) {
this.offset = offset;
}

/**
* @return The first path segment
*/
public String head() {
return components[offset];
}

/**
* @return All path segments except the first
*/
public RoutingPath tail() {
if (!hasTail()) {
throw new IllegalStateException("Routing path is done.");
Expand All @@ -28,14 +40,23 @@ public RoutingPath tail() {
return new RoutingPath(this.components, this.offset + 1);
}

/**
* @return True, if the tail has at least 0 elements
*/
public boolean hasTail() {
return this.components.length > this.offset;
}

/**
* @return True, if there are no segments in this path
*/
public boolean isEmpty() {
return this.offset == this.components.length;
}

/**
* @return The remaining path as a string
*/
public String asPath() {
StringBuilder builder = new StringBuilder();

Expand Down
6 changes: 6 additions & 0 deletions cli/src/main/java/de/jplag/cli/server/RoutingResources.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

import com.sun.net.httpserver.HttpExchange;

/**
* Responds with data from the resources
*/
public class RoutingResources implements Routing {
private String prefix;

/**
* @param prefix The prefix to use within the resources
*/
public RoutingResources(String prefix) {
this.prefix = prefix;

Expand Down
8 changes: 8 additions & 0 deletions cli/src/main/java/de/jplag/cli/server/RoutingStaticFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@

import com.sun.net.httpserver.HttpExchange;

/**
* Responds with a given file
*/
public class RoutingStaticFile implements Routing {
private final byte[] data;
private final ContentType contentType;

/**
* @param file The file to use
* @param contentType The type of content in the file
* @throws IOException If the file cannot be read
*/
public RoutingStaticFile(File file, ContentType contentType) throws IOException {
if (file != null) {
try (FileInputStream inputStream = new FileInputStream(file)) {
Expand Down
21 changes: 21 additions & 0 deletions cli/src/main/java/de/jplag/cli/server/RoutingTree.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,42 @@

import org.apache.commons.lang3.tuple.Pair;

/**
* Manages the tree of paths handled by the web server
*/
public class RoutingTree {
private final RoutingTreeNode root;

/**
* Creates an empty tree
*/
public RoutingTree() {
this.root = new RoutingTreeNode();
}

/**
* Adds a new routing to the tree
* @param path The path to use the routing for
* @param routing The routing
*/
public void insertRouting(RoutingPath path, Routing routing) {
this.root.buildRouting(path, routing);
}

/**
* Adds a new routing to the tree
* @param path The path to use the routing for
* @param routing The routing
*/
public void insertRouting(String path, Routing routing) {
this.insertRouting(new RoutingPath(path), routing);
}

/**
* Gets the routing for a given path
* @param path The path to look up
* @return The remaining path to be handled by the routing and the found routing
*/
public Pair<RoutingPath, Routing> resolveRouting(RoutingPath path) {
return this.root.resolve(path);
}
Expand Down
Loading

0 comments on commit 71d094c

Please sign in to comment.