Skip to content

Commit

Permalink
Fixed issue where resources did not load when running JAR
Browse files Browse the repository at this point in the history
  • Loading branch information
mnordahl committed Jul 13, 2024
1 parent d9e2e28 commit db4a75f
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 57 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@

src/main/resources/examples/_example_list

# Created by https://www.toptal.com/developers/gitignore/api/eclipse,visualstudiocode,intellij,java,gradle,maven,macos,netbeans
# Edit at https://www.toptal.com/developers/gitignore?templates=eclipse,visualstudiocode,intellij,java,gradle,maven,macos,netbeans

Expand Down
33 changes: 31 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ plugins {
id 'application'
}

// Set project properties
group 'dod-c3pu'
version '0.2'
version 'v0.1'
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17

repositories {
mavenCentral()
Expand Down Expand Up @@ -92,10 +95,36 @@ tasks.withType(Test) {
}
}

task generateExampleList {
doLast {
// Define the directory and output file
def examplesDir = new File('src/main/resources/examples')
def outputFile = new File('src/main/resources/examples/_example_list')

// Ensure the output file exists
outputFile.text = ''

// List files and write their names to the output file
examplesDir.eachFile { File file ->
if (file.isFile() && file.name.endsWith('.txt')) {
outputFile.append(file.name + '\n')
}
}
}
}

// Ensure this task is run before the jar is built
jar.dependsOn(generateExampleList)


// Create a FAT JAR including all dependencies
jar {
archiveBaseName.set('c3pu')
archiveVersion.set(version)
manifest {
attributes 'Main-Class': 'view.Main'
attributes 'Main-Class': 'view.Main',
'Implementation-Title': archiveBaseName.get(),
'Implementation-Version': archiveVersion.get()
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
Expand Down
133 changes: 87 additions & 46 deletions src/main/java/util/ExamplesHandler.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
Expand All @@ -19,67 +23,104 @@
public class ExamplesHandler {

private static final String EXAMPLES_DIR = "/examples/";
private static final String EXAMPLES_LIST_FILE = EXAMPLES_DIR + "_example_list";

private static Map<String, Path> exampleMap = null;
private static Map<String, String[]> exampleMap = null;

private ExamplesHandler() {}

private static Map<String, Path> getExampleMap() {
private static Map<String, String[]> getExampleMap() {
if (exampleMap == null) {
// Read examples in one of two ways:
// 1. If running from from the source via Gradle, e.g. in your IDE or terminal, list the files
// in the examples dir and load them.

try {
exampleMap =
Arrays.stream(
Objects.requireNonNull(
new File(ExamplesHandler.class.getResource(EXAMPLES_DIR).toURI())
.listFiles()))
.map(File::toPath) // Convert File to Path
.collect(
Collectors.toMap(
path -> {
// Process the file name to create a readable name
String name = path.getFileName().toString();
name = name.substring(0, name.lastIndexOf('.'));
name = name.replace('_', ' ');
name = name.substring(0, 1).toUpperCase() + name.substring(1);
return name;
},
path -> path // Use the Path object itself as the map value
));
} catch (URISyntaxException e) {
e.printStackTrace();
URI uri = ExamplesHandler.class.getResource(EXAMPLES_DIR).toURI();
// Check if uri points to a file (directory), or just a resource in a JAR
if (uri.getScheme().equals("file")) {
exampleMap =
Files.list(Paths.get(uri))
.filter(Files::isRegularFile)
.filter(path -> path.getFileName().toString().endsWith(".txt"))
.collect(
Collectors.toMap(
path -> nameFromPath(path.getFileName().toString()),
path -> {
// Load the file from the file system
try (BufferedReader reader =
new BufferedReader(new FileReader(path.toFile()))) {
return reader.lines().toArray(String[]::new);
} catch (Exception e) {
return new String[0];
}
}));
}
} catch (URISyntaxException | IOException e) {
// Ignore
exampleMap = null;
}

// 2. If running from a JAR, files in examples dir cannot be listed. Instead, first read the
// special file that contains their names, and then load them explicitly.
if (exampleMap == null) {
// Read the list of examples from the _example_list file using getResourceAsStream
try (BufferedReader reader =
new BufferedReader(
new InputStreamReader(
ExamplesHandler.class.getResourceAsStream(EXAMPLES_LIST_FILE)))) {
Map<String, String[]> tmpMap = new HashMap<>();
String line;
while ((line = reader.readLine()) != null) {
URL fileURL = ExamplesHandler.class.getResource(EXAMPLES_DIR + line);
if (fileURL != null) {
try (BufferedReader fileReader =
new BufferedReader(new InputStreamReader(fileURL.openStream()))) {
tmpMap.put(nameFromPath(line), fileReader.lines().toArray(String[]::new));
}
}
}
exampleMap = tmpMap;
} catch (Exception e) {
// Ignore
exampleMap = null;
}
}

if (exampleMap == null) {
exampleMap = Collections.emptyMap();
}
}
return exampleMap;
}

private static String nameFromPath(final String filename) {
// Process the file name to create a readable name
String name = filename;
name = name.substring(0, name.lastIndexOf('.'));
name = name.replace('_', ' ');
name = name.substring(0, 1).toUpperCase() + name.substring(1);
return name;
}

public static List<String> getExampleNames() {
return getExampleMap().keySet().stream().sorted().collect(Collectors.toList());
}

public static String[] getExample(String name) {
Path path = getExampleMap().get(name);
if (path == null) {
return new String[0];
}
try (BufferedReader reader = new BufferedReader(new FileReader(path.toFile()))) {
String[] lines =
reader
.lines()
.map(s -> s.split("(//|#|%)", 2)[0])
.map(s -> s.replace(" ", ""))
.toArray(String[]::new);
// verify that each line contains only 0s and 1s, and is 8 characters long
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
if (line.length() != 8 || !line.matches("[01]+")) {
throw new IllegalArgumentException(
String.format("Invalid file format at line %d: '%s'", (i + 1), line));
}
String[] lines =
Arrays.stream(getExampleMap().get(name))
.map(s -> s.split("(//|#|%)", 2)[0])
.map(s -> s.replace(" ", ""))
.toArray(String[]::new);
// verify that each line contains only 0s and 1s, and is 8 characters long
for (int i = 0; i < lines.length; i++) {
String line = lines[i];
if (line.length() != 8 || !line.matches("[01]+")) {
throw new IllegalArgumentException(
String.format("Invalid file format at line %d: '%s'", (i + 1), line));
}
return lines;
} catch (Exception e) {
return new String[0];
}
return lines;
}
}
13 changes: 4 additions & 9 deletions src/main/java/view/HelpWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
import static util.LazySwing.inv;

import java.io.IOException;
import java.net.URISyntaxException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
Expand Down Expand Up @@ -52,16 +49,14 @@ public HelpWindow(JFrame parent, Settings settings) {
// Schedule a non-EDT task to load the html content
new Thread(
() -> {
Path path;
try {
path = Paths.get(helpUrl.toURI());
byte[] fileBytes = Files.readAllBytes(path);
try (InputStream inputStream = getClass().getResourceAsStream("/help/help.html")) {
byte[] fileBytes = inputStream.readAllBytes();
inv(
() -> {
helpContent.setText(new String(fileBytes, StandardCharsets.UTF_8));
helpContent.setCaretPosition(0);
});
} catch (URISyntaxException | IOException e) {
} catch (IOException e) {
inv(
() ->
helpContent.setText(
Expand Down
2 changes: 2 additions & 0 deletions todo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@
[x] Update example programs, after instruction changes (again...)
[] Add config/view option to turn off auto scroll to active cell
[] Think about: Should conditional jump use another dst register, e.g. R2? (Instead of RES)
[x] Resources failed to load when building and running from JAR. Fix!
[] Set up a Logger, that can collect errors in a local file.$
[]
0100 1010
0001 0000
Expand Down

0 comments on commit db4a75f

Please sign in to comment.