diff --git a/merge_sort_java/pom.xml b/merge_sort_java/pom.xml
new file mode 100644
index 0000000..edb39b4
--- /dev/null
+++ b/merge_sort_java/pom.xml
@@ -0,0 +1,46 @@
+
+
+ 4.0.0
+
+ com.mergesort
+ merge-sort-example
+ 1.0-SNAPSHOT
+ jar
+
+ Merge Sort Example
+ Java rebuild of COBOL merge_sort_test.cbl - Testing sort and merge on customer test data
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.3.0
+
+
+
+ com.mergesort.MergeSortExample
+
+
+
+
+
+
+
diff --git a/merge_sort_java/src/main/java/com/mergesort/CustomerRecord.java b/merge_sort_java/src/main/java/com/mergesort/CustomerRecord.java
new file mode 100644
index 0000000..76fecf6
--- /dev/null
+++ b/merge_sort_java/src/main/java/com/mergesort/CustomerRecord.java
@@ -0,0 +1,91 @@
+package com.mergesort;
+
+import java.util.Comparator;
+
+public class CustomerRecord {
+
+ public static final Comparator BY_CUSTOMER_ID_ASC =
+ Comparator.comparingInt(CustomerRecord::getCustomerId);
+
+ public static final Comparator BY_CONTRACT_ID_DESC =
+ Comparator.comparingInt(CustomerRecord::getContractId).reversed();
+
+ private int customerId;
+ private String lastName;
+ private String firstName;
+ private int contractId;
+ private String comment;
+
+ public CustomerRecord(int customerId, String lastName, String firstName,
+ int contractId, String comment) {
+ this.customerId = customerId;
+ this.lastName = lastName;
+ this.firstName = firstName;
+ this.contractId = contractId;
+ this.comment = comment;
+ }
+
+ public int getCustomerId() {
+ return customerId;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public int getContractId() {
+ return contractId;
+ }
+
+ public String getComment() {
+ return comment;
+ }
+
+ public String toFileString() {
+ return String.format("%05d%-50s%-50s%05d%-25s",
+ customerId, lastName, firstName, contractId, comment);
+ }
+
+ public static CustomerRecord fromFileString(String line) {
+ if (line.length() < 135) {
+ line = String.format("%-135s", line);
+ }
+ int id = Integer.parseInt(line.substring(0, 5).trim());
+ String last = line.substring(5, 55).trim();
+ String first = line.substring(55, 105).trim();
+ int contract = Integer.parseInt(line.substring(105, 110).trim());
+ String cmt = line.substring(110, 135).trim();
+ return new CustomerRecord(id, last, first, contract, cmt);
+ }
+
+ @Override
+ public String toString() {
+ return toFileString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CustomerRecord that = (CustomerRecord) o;
+ return customerId == that.customerId
+ && contractId == that.contractId
+ && lastName.equals(that.lastName)
+ && firstName.equals(that.firstName)
+ && comment.equals(that.comment);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = customerId;
+ result = 31 * result + lastName.hashCode();
+ result = 31 * result + firstName.hashCode();
+ result = 31 * result + contractId;
+ result = 31 * result + comment.hashCode();
+ return result;
+ }
+}
diff --git a/merge_sort_java/src/main/java/com/mergesort/MergeSortExample.java b/merge_sort_java/src/main/java/com/mergesort/MergeSortExample.java
new file mode 100644
index 0000000..6933794
--- /dev/null
+++ b/merge_sort_java/src/main/java/com/mergesort/MergeSortExample.java
@@ -0,0 +1,107 @@
+package com.mergesort;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MergeSortExample {
+
+ private final Path workDir;
+
+ public MergeSortExample(Path workDir) {
+ this.workDir = workDir;
+ }
+
+ public static void main(String[] args) throws IOException {
+ Path dir = Path.of(System.getProperty("user.dir"));
+ MergeSortExample app = new MergeSortExample(dir);
+ app.run();
+ }
+
+ public void run() throws IOException {
+ createTestData();
+ mergeAndDisplayFiles();
+ sortAndDisplayFile();
+ System.out.println("Done.");
+ }
+
+ void createTestData() throws IOException {
+ System.out.println("Creating test data files...");
+
+ List eastRecords = List.of(
+ new CustomerRecord(1, "last-1", "first-1", 5423, "comment-1"),
+ new CustomerRecord(5, "last-5", "first-5", 12323, "comment-5"),
+ new CustomerRecord(10, "last-10", "first-10", 653, "comment-10"),
+ new CustomerRecord(50, "last-50", "first-50", 5050, "comment-50"),
+ new CustomerRecord(25, "last-25", "first-25", 7725, "comment-25"),
+ new CustomerRecord(75, "last-75", "first-75", 1175, "comment-75")
+ );
+ writeRecords(workDir.resolve("test-file-1.txt"), eastRecords);
+
+ List westRecords = List.of(
+ new CustomerRecord(999, "last-999", "first-999", 1610, "comment-99"),
+ new CustomerRecord(3, "last-03", "first-03", 3331, "comment-03"),
+ new CustomerRecord(30, "last-30", "first-30", 8765, "comment-30"),
+ new CustomerRecord(85, "last-85", "first-85", 4567, "comment-85"),
+ new CustomerRecord(24, "last-24", "first-24", 247, "comment-24")
+ );
+ writeRecords(workDir.resolve("test-file-2.txt"), westRecords);
+ }
+
+ void mergeAndDisplayFiles() throws IOException {
+ System.out.println("Merging and sorting files...");
+
+ List file1Records = readRecords(workDir.resolve("test-file-1.txt"));
+ List file2Records = readRecords(workDir.resolve("test-file-2.txt"));
+
+ List merged = new ArrayList<>();
+ merged.addAll(file1Records);
+ merged.addAll(file2Records);
+ merged.sort(CustomerRecord.BY_CUSTOMER_ID_ASC);
+
+ writeRecords(workDir.resolve("merge-output.txt"), merged);
+
+ for (CustomerRecord record : merged) {
+ System.out.println(record);
+ }
+ }
+
+ void sortAndDisplayFile() throws IOException {
+ System.out.println("Sorting merged file on descending contract id....");
+
+ List mergedRecords = readRecords(workDir.resolve("merge-output.txt"));
+ mergedRecords.sort(CustomerRecord.BY_CONTRACT_ID_DESC);
+
+ writeRecords(workDir.resolve("sorted-contract-id.txt"), mergedRecords);
+
+ for (CustomerRecord record : mergedRecords) {
+ System.out.println(record);
+ }
+ }
+
+ List readRecords(Path file) throws IOException {
+ List records = new ArrayList<>();
+ try (BufferedReader reader = Files.newBufferedReader(file)) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ if (!line.isBlank()) {
+ records.add(CustomerRecord.fromFileString(line));
+ }
+ }
+ }
+ return records;
+ }
+
+ void writeRecords(Path file, List records) throws IOException {
+ try (BufferedWriter writer = Files.newBufferedWriter(file)) {
+ for (CustomerRecord record : records) {
+ writer.write(record.toFileString());
+ writer.newLine();
+ }
+ }
+ }
+}
diff --git a/merge_sort_java/src/test/java/com/mergesort/MergeSortExampleTest.java b/merge_sort_java/src/test/java/com/mergesort/MergeSortExampleTest.java
new file mode 100644
index 0000000..d740fe1
--- /dev/null
+++ b/merge_sort_java/src/test/java/com/mergesort/MergeSortExampleTest.java
@@ -0,0 +1,116 @@
+package com.mergesort;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class MergeSortExampleTest {
+
+ private Path tempDir;
+ private MergeSortExample app;
+
+ @Before
+ public void setUp() throws IOException {
+ tempDir = Files.createTempDirectory("merge-sort-test");
+ app = new MergeSortExample(tempDir);
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ Files.walk(tempDir)
+ .sorted(java.util.Comparator.reverseOrder())
+ .forEach(p -> {
+ try { Files.deleteIfExists(p); } catch (IOException ignored) {}
+ });
+ }
+
+ @Test
+ public void testCreateTestData() throws IOException {
+ app.createTestData();
+
+ Path file1 = tempDir.resolve("test-file-1.txt");
+ Path file2 = tempDir.resolve("test-file-2.txt");
+ assertTrue("test-file-1.txt should exist", Files.exists(file1));
+ assertTrue("test-file-2.txt should exist", Files.exists(file2));
+
+ List lines1 = Files.readAllLines(file1);
+ assertEquals("East file should have 6 records", 6, lines1.size());
+
+ List lines2 = Files.readAllLines(file2);
+ assertEquals("West file should have 5 records", 5, lines2.size());
+ }
+
+ @Test
+ public void testMergeAndDisplayFiles() throws IOException {
+ app.createTestData();
+ app.mergeAndDisplayFiles();
+
+ Path mergedFile = tempDir.resolve("merge-output.txt");
+ assertTrue("merge-output.txt should exist", Files.exists(mergedFile));
+
+ List records = app.readRecords(mergedFile);
+ assertEquals("Merged file should have 11 records", 11, records.size());
+
+ for (int i = 1; i < records.size(); i++) {
+ assertTrue("Records should be sorted by customer ID ascending",
+ records.get(i).getCustomerId() >= records.get(i - 1).getCustomerId());
+ }
+
+ assertEquals(1, records.get(0).getCustomerId());
+ assertEquals(3, records.get(1).getCustomerId());
+ assertEquals(5, records.get(2).getCustomerId());
+ assertEquals(999, records.get(10).getCustomerId());
+ }
+
+ @Test
+ public void testSortAndDisplayFile() throws IOException {
+ app.createTestData();
+ app.mergeAndDisplayFiles();
+ app.sortAndDisplayFile();
+
+ Path sortedFile = tempDir.resolve("sorted-contract-id.txt");
+ assertTrue("sorted-contract-id.txt should exist", Files.exists(sortedFile));
+
+ List records = app.readRecords(sortedFile);
+ assertEquals("Sorted file should have 11 records", 11, records.size());
+
+ for (int i = 1; i < records.size(); i++) {
+ assertTrue("Records should be sorted by contract ID descending",
+ records.get(i).getContractId() <= records.get(i - 1).getContractId());
+ }
+
+ assertEquals(12323, records.get(0).getContractId());
+ assertEquals(247, records.get(10).getContractId());
+ }
+
+ @Test
+ public void testCustomerRecordRoundTrip() {
+ CustomerRecord original = new CustomerRecord(42, "Smith", "John", 12345, "test-comment");
+ String fileString = original.toFileString();
+ CustomerRecord parsed = CustomerRecord.fromFileString(fileString);
+
+ assertEquals(original.getCustomerId(), parsed.getCustomerId());
+ assertEquals(original.getLastName(), parsed.getLastName());
+ assertEquals(original.getFirstName(), parsed.getFirstName());
+ assertEquals(original.getContractId(), parsed.getContractId());
+ assertEquals(original.getComment(), parsed.getComment());
+ }
+
+ @Test
+ public void testFullRun() throws IOException {
+ app.run();
+
+ assertTrue(Files.exists(tempDir.resolve("test-file-1.txt")));
+ assertTrue(Files.exists(tempDir.resolve("test-file-2.txt")));
+ assertTrue(Files.exists(tempDir.resolve("merge-output.txt")));
+ assertTrue(Files.exists(tempDir.resolve("sorted-contract-id.txt")));
+ }
+}