diff --git a/java-merge-sort/README.md b/java-merge-sort/README.md new file mode 100644 index 0000000..de2e36a --- /dev/null +++ b/java-merge-sort/README.md @@ -0,0 +1,72 @@ +# Java Merge Sort Implementation + +This is a Java conversion of the COBOL merge sort example found in `../merge_sort/merge_sort_test.cbl`. + +## Overview + +The implementation provides equivalent functionality to the original COBOL program: + +1. **CustomerRecord Class**: Represents customer data with fields matching the COBOL structure +2. **MergeSortProcessor**: Handles file operations, merging, and sorting +3. **MergeSortMain**: Main application that orchestrates the workflow + +## Features + +- Creates test data programmatically (matching COBOL test data) +- Merges two sorted files by customer ID in ascending order +- Sorts merged file by contract ID in descending order +- Displays results after each operation +- Proper file I/O with exception handling + +## Data Structure + +The `CustomerRecord` class implements `Comparable` and contains: +- `customerId` (int) - 5-digit customer identifier +- `lastName` (String) - Customer last name (up to 50 characters) +- `firstName` (String) - Customer first name (up to 50 characters) +- `contractId` (int) - 5-digit contract identifier +- `comment` (String) - Comment field (up to 25 characters) + +## Usage + +### Compilation +```bash +javac -d . src/main/java/com/example/mergesort/*.java +``` + +### Execution +```bash +java com.example.mergesort.MergeSortMain +``` + +## Workflow + +1. **Create Test Data**: Generates two test files with sample customer records +2. **Merge Files**: Merges the two files, sorting by customer ID ascending +3. **Sort by Contract ID**: Sorts the merged file by contract ID descending +4. **Display Results**: Shows the contents after each operation + +## Files Generated + +- `test-file-1.txt` - First test data file +- `test-file-2.txt` - Second test data file +- `merge-output.txt` - Merged and sorted output +- `sorted-contract-id.txt` - Final sorted output by contract ID + +## Differences from COBOL Version + +- Uses in-memory collections instead of direct file processing +- Leverages Java's built-in sorting capabilities +- Implements proper object-oriented design patterns +- Uses modern Java I/O APIs for file handling + +## Test Data + +The implementation creates the same test data as the COBOL version: + +**File 1**: Customer IDs 1, 5, 10, 25, 50, 75 +**File 2**: Customer IDs 3, 24, 30, 85, 999 + +After merging and sorting by customer ID: 1, 3, 5, 10, 24, 25, 30, 50, 75, 85, 999 + +After sorting by contract ID (descending): Records ordered by contract ID from highest to lowest. diff --git a/java-merge-sort/src/main/java/com/example/mergesort/CustomerRecord.java b/java-merge-sort/src/main/java/com/example/mergesort/CustomerRecord.java new file mode 100644 index 0000000..9e72a3c --- /dev/null +++ b/java-merge-sort/src/main/java/com/example/mergesort/CustomerRecord.java @@ -0,0 +1,97 @@ +package com.example.mergesort; + +public class CustomerRecord implements Comparable { + private int customerId; + private String lastName; + private String firstName; + private int contractId; + private String comment; + + public CustomerRecord() { + } + + 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 void setCustomerId(int customerId) { + this.customerId = customerId; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public int getContractId() { + return contractId; + } + + public void setContractId(int contractId) { + this.contractId = contractId; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + @Override + public int compareTo(CustomerRecord other) { + return Integer.compare(this.customerId, other.customerId); + } + + @Override + public String toString() { + return String.format("%05d%-50s%-50s%05d%-25s", + customerId, + padRight(lastName, 50), + padRight(firstName, 50), + contractId, + padRight(comment, 25)); + } + + private String padRight(String str, int length) { + if (str == null) str = ""; + if (str.length() >= length) { + return str.substring(0, length); + } + return str + " ".repeat(length - str.length()); + } + + public static CustomerRecord fromString(String line) { + if (line == null || line.length() < 135) { + throw new IllegalArgumentException("Invalid record format"); + } + + int customerId = Integer.parseInt(line.substring(0, 5)); + String lastName = line.substring(5, 55).trim(); + String firstName = line.substring(55, 105).trim(); + int contractId = Integer.parseInt(line.substring(105, 110)); + String comment = line.substring(110, 135).trim(); + + return new CustomerRecord(customerId, lastName, firstName, contractId, comment); + } +} diff --git a/java-merge-sort/src/main/java/com/example/mergesort/MergeSortMain.java b/java-merge-sort/src/main/java/com/example/mergesort/MergeSortMain.java new file mode 100644 index 0000000..51a2571 --- /dev/null +++ b/java-merge-sort/src/main/java/com/example/mergesort/MergeSortMain.java @@ -0,0 +1,94 @@ +package com.example.mergesort; + +import java.io.*; +import java.nio.file.*; +import java.util.*; + +public class MergeSortMain { + + private static final String TEST_FILE_1 = "test-file-1.txt"; + private static final String TEST_FILE_2 = "test-file-2.txt"; + private static final String MERGED_FILE = "merge-output.txt"; + private static final String SORTED_FILE = "sorted-contract-id.txt"; + + private MergeSortProcessor processor; + + public MergeSortMain() { + this.processor = new MergeSortProcessor(); + } + + public static void main(String[] args) { + MergeSortMain app = new MergeSortMain(); + + try { + app.createTestData(); + app.mergeAndDisplayFiles(); + app.sortAndDisplayFile(); + + System.out.println("Done."); + + } catch (Exception e) { + System.err.println("Error: " + e.getMessage()); + e.printStackTrace(); + } + } + + public void createTestData() { + System.out.println("Creating test data files..."); + + try { + createTestFile1(); + createTestFile2(); + } catch (IOException e) { + throw new RuntimeException("Failed to create test data: " + e.getMessage(), e); + } + } + + private void createTestFile1() throws IOException { + List records = Arrays.asList( + 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") + ); + + writeRecordsToFile(records, TEST_FILE_1); + } + + private void createTestFile2() throws IOException { + List records = Arrays.asList( + 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") + ); + + writeRecordsToFile(records, TEST_FILE_2); + } + + private void writeRecordsToFile(List records, String fileName) throws IOException { + try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(fileName))) { + for (CustomerRecord record : records) { + writer.write(record.toString()); + writer.newLine(); + } + } + } + + public void mergeAndDisplayFiles() { + System.out.println("Merging and sorting files..."); + + processor.mergeFiles(TEST_FILE_1, TEST_FILE_2, MERGED_FILE); + processor.displayFile(MERGED_FILE, "Merged file contents:"); + } + + public void sortAndDisplayFile() { + System.out.println("Sorting merged file on descending contract id...."); + + processor.sortFileByContractId(MERGED_FILE, SORTED_FILE); + processor.displayFile(SORTED_FILE, "Sorted file contents:"); + } +} diff --git a/java-merge-sort/src/main/java/com/example/mergesort/MergeSortProcessor.java b/java-merge-sort/src/main/java/com/example/mergesort/MergeSortProcessor.java new file mode 100644 index 0000000..a40bb68 --- /dev/null +++ b/java-merge-sort/src/main/java/com/example/mergesort/MergeSortProcessor.java @@ -0,0 +1,103 @@ +package com.example.mergesort; + +import java.io.*; +import java.nio.file.*; +import java.util.*; +import java.util.stream.Collectors; + +public class MergeSortProcessor { + + public void mergeFiles(String file1Path, String file2Path, String outputPath) { + try { + List records1 = readRecordsFromFile(file1Path); + List records2 = readRecordsFromFile(file2Path); + + Collections.sort(records1); + Collections.sort(records2); + + List mergedRecords = mergeSortedLists(records1, records2); + + writeRecordsToFile(mergedRecords, outputPath); + + } catch (IOException e) { + throw new RuntimeException("Error merging files: " + e.getMessage(), e); + } + } + + public void sortFileByContractId(String inputPath, String outputPath) { + try { + List records = readRecordsFromFile(inputPath); + + records.sort((r1, r2) -> Integer.compare(r2.getContractId(), r1.getContractId())); + + writeRecordsToFile(records, outputPath); + + } catch (IOException e) { + throw new RuntimeException("Error sorting file: " + e.getMessage(), e); + } + } + + private List readRecordsFromFile(String filePath) throws IOException { + List records = new ArrayList<>(); + + try (BufferedReader reader = Files.newBufferedReader(Paths.get(filePath))) { + String line; + while ((line = reader.readLine()) != null) { + if (!line.trim().isEmpty()) { + records.add(CustomerRecord.fromString(line)); + } + } + } + + return records; + } + + private void writeRecordsToFile(List records, String filePath) throws IOException { + try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(filePath))) { + for (CustomerRecord record : records) { + writer.write(record.toString()); + writer.newLine(); + } + } + } + + private List mergeSortedLists(List list1, List list2) { + List merged = new ArrayList<>(); + int i = 0, j = 0; + + while (i < list1.size() && j < list2.size()) { + if (list1.get(i).compareTo(list2.get(j)) <= 0) { + merged.add(list1.get(i)); + i++; + } else { + merged.add(list2.get(j)); + j++; + } + } + + while (i < list1.size()) { + merged.add(list1.get(i)); + i++; + } + + while (j < list2.size()) { + merged.add(list2.get(j)); + j++; + } + + return merged; + } + + public void displayFile(String filePath, String description) { + try { + System.out.println(description); + List records = readRecordsFromFile(filePath); + for (CustomerRecord record : records) { + System.out.println(record); + } + System.out.println(); + } catch (IOException e) { + System.err.println("Error reading file " + filePath + ": " + e.getMessage()); + } + } +}