Skip to content

Refactor Network Analyser for Modularity and Performance#1

Open
zhenyuefu wants to merge 2 commits intomasterfrom
refactor/modular-network-analyzer-4288025737854752343
Open

Refactor Network Analyser for Modularity and Performance#1
zhenyuefu wants to merge 2 commits intomasterfrom
refactor/modular-network-analyzer-4288025737854752343

Conversation

@zhenyuefu
Copy link
Owner

This PR completely refactors the Network Analyser application to address performance issues, improve code modularity, and enhance the user interface.

Key Changes:

  • Architecture: Moved from a monolithic structure to a layered architecture (Model, Service, UI).
  • Model: Replaced the deep inheritance hierarchy (IPPacket extends EthernetPacket) with a composition-based approach where a Packet holds raw data and specific Header classes parse protocols on demand. This improves flexibility and correctness.
  • Parsing: Replaced the inefficient PacketAnalyser with a new HexDumpParser that reads files line-by-line and handles large files more gracefully.
  • UI:
    • Performance: Used PacketViewModel for the TableView to efficiently display packet summaries.
    • Responsiveness: Implemented background loading for file operations using JavaFX Task.
    • Layout: Updated net.fxml to use BorderPane and SplitPane for a resizable and modern layout.
    • Features: Added a Hex View to inspect raw packet bytes and a Status Bar for feedback.
  • Testing: Added unit tests for the parser and protocol header decoding to ensure correctness.

PR created automatically by Jules for task 4288025737854752343 started by @zhenyuefu

- Restructured project into `model`, `service`, `ui` packages.
- Introduced `Packet` model with composition-based protocol headers (`EthernetHeader`, `IPHeader`, etc.) replacing inheritance.
- Implemented `HexDumpParser` in `service` for robust and efficient file parsing.
- Refactored UI to use `PacketViewModel` and `PacketTreeBuilder` for better separation of concerns and performance.
- Added background file loading using `Task` to prevent UI freezing.
- Enhanced UI with SplitPane layout, Hex View, and Status Bar.
- Re-implemented Export functionality.
- Added unit tests for parser and protocol headers.

Co-authored-by: zhenyuefu <56567636+zhenyuefu@users.noreply.github.com>
@google-labs-jules
Copy link

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings February 12, 2026 08:10
Changed `on: create` to `on: push` with `tags: ['*']`. The previous configuration triggered the release workflow on branch creation, which caused failures because `action-gh-release` expects a tag ref. This ensures the workflow only runs when a tag is pushed.

Co-authored-by: zhenyuefu <56567636+zhenyuefu@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the Network Analyser into a more modular Model/Service/UI structure, replacing the prior inheritance-heavy packet model and parser with composition-based headers and a streaming hexdump parser, alongside a refreshed JavaFX UI (table + protocol tree + hex view + status bar).

Changes:

  • Introduces composition-based packet/header model (Packet, EthernetHeader, IPHeader, UDPHeader, DNSHeader, DHCPHeader).
  • Replaces parsing with HexDumpParser and adds unit tests for parsing and header decoding.
  • Updates JavaFX UI layout (net.fxml) and controller logic for background load/export plus new hex/status views.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/main/java/projectreseau/networkanalyser/MainController.java Refactored controller to load/export in background, bind TableView to PacketViewModel, and populate tree + hex views.
src/main/resources/projectreseau/networkanalyser/net.fxml Moves to BorderPane/SplitPane layout; adds hex view and status bar.
src/main/java/projectreseau/networkanalyser/service/HexDumpParser.java New line-by-line hexdump parser producing model.Packet instances.
src/main/java/projectreseau/networkanalyser/ui/PacketViewModel.java New view model deriving table fields from parsed headers.
src/main/java/projectreseau/networkanalyser/ui/PacketTreeBuilder.java Builds protocol detail tree from headers for UI/export.
src/main/java/projectreseau/networkanalyser/model/Packet.java New raw-packet container with id/length/data.
src/main/java/projectreseau/networkanalyser/model/EthernetHeader.java Ethernet header decoding utilities.
src/main/java/projectreseau/networkanalyser/model/IPHeader.java IPv4 header decoding utilities.
src/main/java/projectreseau/networkanalyser/model/UDPHeader.java UDP header decoding utilities.
src/main/java/projectreseau/networkanalyser/model/DNSHeader.java DNS header decoding utilities.
src/main/java/projectreseau/networkanalyser/model/DHCPHeader.java DHCP/BOOTP header field accessors used for tree display.
src/test/java/projectreseau/networkanalyser/service/HexDumpParserTest.java Tests parsing multiple packets from string input.
src/test/java/projectreseau/networkanalyser/model/ProtocolHeaderTest.java Tests Ethernet and IPv4 header field decoding.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +15 to +21
EthernetHeader eth = new EthernetHeader(packet.getData(), 0);
String p = eth.getTypeDescription();
String s = eth.getSourceMac();
String d = eth.getDestinationMac();
String i = "";

try {
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The initial Ethernet parsing (getTypeDescription(), getSourceMac(), getDestinationMac()) happens before the try block. If the packet is truncated (< 14 bytes) this can throw and prevent the table from loading. Consider moving the Ethernet parsing inside the try (or validating length first) and falling back to safe defaults on failure.

Suggested change
EthernetHeader eth = new EthernetHeader(packet.getData(), 0);
String p = eth.getTypeDescription();
String s = eth.getSourceMac();
String d = eth.getDestinationMac();
String i = "";
try {
String p = "Unknown";
String s = "";
String d = "";
String i = "";
try {
EthernetHeader eth = new EthernetHeader(packet.getData(), 0);
p = eth.getTypeDescription();
s = eth.getSourceMac();
d = eth.getDestinationMac();

Copilot uses AI. Check for mistakes.
Comment on lines +96 to +101
task.setOnSucceeded(e -> {
List<Packet> packets = task.getValue();
packetList.clear();
packetList.addAll(packets.stream().map(PacketViewModel::new).collect(Collectors.toList()));
if (statusLabel != null) statusLabel.setText("Loaded " + packets.size() + " packets from " + file.getName());
});
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PacketViewModel instances are created in setOnSucceeded, which runs on the JavaFX Application Thread. For large captures, this will freeze the UI even though file parsing was offloaded. Consider doing the packets -> PacketViewModel transformation inside the Task.call() and only applying the final list to packetList on success.

Copilot uses AI. Check for mistakes.
Comment on lines +169 to 181
Task<Void> task = new Task<>() {
@Override
protected Void call() throws Exception {
try (java.io.PrintWriter writer = new java.io.PrintWriter(file)) {
for (PacketViewModel pvm : packetList) {
Packet packet = pvm.getPacket();
TreeItem<String> root = PacketTreeBuilder.build(packet);
dumpTree(writer, root, "");
writer.println();
writer.println("--------------------------------------------------");
writer.println();
}
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exportPackets iterates over packetList from the background Task thread. ObservableList is not thread-safe, and this can race with UI updates (or throw during iteration). Snapshot the current items on the FX thread before starting the task (e.g., copy to a plain List) and iterate over that snapshot in the background.

Copilot uses AI. Check for mistakes.
Comment on lines +111 to 112
new Thread(task).start();
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both loadPackets and exportPackets start raw Threads without setting them as daemon or using a managed executor. Non-daemon threads can keep the JVM alive after the window closes, and unmanaged threads make cancellation/lifecycle harder. Prefer an ExecutorService (or set thread name + daemon) and consider wiring Task cancellation to UI actions.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +32
List<Packet> packets = new ArrayList<>();
int packetId = 1;
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int expectedOffset = 0; // The next expected byte offset within the current packet

Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HexDumpParser uses an unbounded ByteArrayOutputStream for packet accumulation. If the input is malformed (missing a new packet offset) or extremely large, this can grow until OOM. Consider enforcing a maximum packet size (similar to the previous 64KiB snaplength) and terminating/starting a new packet or failing fast when exceeded.

Copilot uses AI. Check for mistakes.
Comment on lines +6 to +12
import java.util.ArrayList;
import java.util.List;

public class HexDumpParser {

public List<Packet> parse(File file) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parse(File) uses FileReader, which relies on the platform default charset. Since the project encoding is UTF-8, consider using an explicit charset (e.g., Files.newBufferedReader(..., UTF_8)) to avoid inconsistent behavior across machines.

Suggested change
import java.util.ArrayList;
import java.util.List;
public class HexDumpParser {
public List<Packet> parse(File file) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
public class HexDumpParser {
public List<Packet> parse(File file) throws IOException {
try (BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {

Copilot uses AI. Check for mistakes.
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 6; i++) {
if (i > 0) sb.append(":");
sb.append(String.format("%02x", bytes[pos + i]));
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extractMac formats signed byte values with %02x, which can produce strings like ffffff8c for bytes >= 0x80. Mask each byte with & 0xFF (or otherwise convert to an unsigned int) before formatting so MAC addresses are always two hex digits per octet; this also makes ProtocolHeaderTest expectations pass.

Suggested change
sb.append(String.format("%02x", bytes[pos + i]));
sb.append(String.format("%02x", bytes[pos + i] & 0xFF));

Copilot uses AI. Check for mistakes.
Comment on lines +128 to +135
for (int j = 0; j < 16; j++) {
if (i + j < data.length) {
sb.append(String.format("%02x ", data[i + j]));
} else {
sb.append(" ");
}
if (j == 7) sb.append(" ");
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String.format("%02x", data[i + j]) formats a signed byte and can output ffffff8c-style values for bytes >= 0x80, which breaks the hex view. Convert the byte to an unsigned int (e.g., mask with & 0xFF) before formatting.

Copilot uses AI. Check for mistakes.

for (int j = 0; j < 16; j++) {
if (i + j < data.length) {
sb.append(String.format("%02x ", data[i + j]));
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This array access might be out of bounds, as the index might be equal to the array length + 14.

Copilot uses AI. Check for mistakes.

for (int j = 0; j < 16; j++) {
if (i + j < data.length) {
char c = (char) (data[i + j] & 0xFF);
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This array access might be out of bounds, as the index might be equal to the array length + 14.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants