Skip to content

Add more commands to JabSrv#14855

Merged
koppor merged 25 commits into
mainfrom
new-task-b2ce
Jan 15, 2026
Merged

Add more commands to JabSrv#14855
koppor merged 25 commits into
mainfrom
new-task-b2ce

Conversation

@koppor

@koppor koppor commented Jan 14, 2026

Copy link
Copy Markdown
Member

User description

Refs #14823 (comment)

We now have "proper" commands

Steps to test

  1. Start JabRef
  2. Enable HTTP server
  3. Open commands.http - execute
  4. Open rest-api.http - scroll down - execute

Mandatory checks

  • I own the copyright of the code submitted and I license it under the MIT license
  • I manually tested my changes in running JabRef (always required)
  • I added JUnit tests for changes (if applicable)
  • [/] I added screenshots in the PR description (if change is visible to the user)
  • I described the change in CHANGELOG.md in a way that is understandable for the average user (if change is visible to the user)
  • [/] I checked the user documentation: Is the information available and up to date? If not, I created an issue at https://github.com/JabRef/user-documentation/issues or, even better, I submitted a pull request updating file(s) in https://github.com/JabRef/user-documentation/tree/main/en.

PR Type

Enhancement


Description

  • Refactored HTTP command architecture to use polymorphic deserialization

  • Added three new HTTP commands: selectentries, open, and focus

  • Renamed JumpToEntryKey to SelectEntryKeys supporting multiple entries

  • Moved UiMessageHandler interface to logic module for better separation

  • Added REST API endpoint for importing BibTeX to current library

  • Improved thread safety with Platform.runLater() for JavaFX operations


Diagram Walkthrough

flowchart LR
  A["HTTP Request"] -->|JSON deserialization| B["Command classes"]
  B -->|polymorphic| C["SelectEntries/Open/Focus"]
  C -->|execute| D["UiCommand creation"]
  D -->|handleUiCommands| E["UiMessageHandler"]
  E -->|Platform.runLater| F["JabRefFrame/ViewModel"]
  F -->|process| G["UI updates"]
Loading

File Walkthrough

Relevant files
Enhancement
15 files
UiCommand.java
Renamed JumpToEntryKey to SelectEntryKeys with list support
+8/-6     
JabRefFrame.java
Registered JabRefFrame as UiMessageHandler with thread safety
+8/-6     
JabRefFrameViewModel.java
Refactored entry selection to support multiple entries     
+39/-25 
ArgumentProcessor.java
Updated to use SelectEntryKeys with list parameter             
+1/-1     
JabRefGUI.java
Pass JabRefFrame to HTTP server manager initialization     
+1/-1     
HttpServerManager.java
Added UiMessageHandler parameter to start methods               
+10/-7   
HttpServerThread.java
Pass UiMessageHandler through to Server initialization     
+11/-2   
Server.java
Register UiMessageHandler in service locator for GUI mode
+17/-1   
Command.java
Refactored to abstract class with polymorphic JSON deserialization
+29/-11 
CommandResource.java
Simplified command dispatch with polymorphic deserialization
+0/-3     
SelectEntriesCommand.java
Simplified to delegate to UiCommand via base class             
+10/-87 
FocusCommand.java
New command to bring JabRef window to front                           
+14/-0   
OpenLibrariesCommand.java
New command to open library files via HTTP                             
+26/-0   
EntriesResource.java
New resource for entries endpoint with BibTeX import         
+93/-0   
ServerUtils.java
Added support for `current` library identifier in GUI mode
+6/-0     
Refactoring
6 files
UiMessageHandler.java
Moved interface from gui.frame to logic package                   
+1/-2     
GeneralTab.java
Updated import to use UiMessageHandler from logic package
+1/-1     
GeneralTabViewModel.java
Updated import to use UiMessageHandler from logic package
+1/-1     
CLIMessageHandler.java
Updated import to use UiMessageHandler from logic package
+1/-1     
EntryResource.java
Moved to resources package and updated package declaration
+1/-3     
LibraryResource.java
Moved PDF files endpoint to EntriesResource                           
+0/-38   
Tests
1 files
FocusCommandTest.java
New test for focus command CLI error handling                       
+33/-0   
Documentation
3 files
commands.http
Updated examples with new command format and focus command
+15/-8   
rest-api.http
Added BibTeX import endpoint documentation                             
+16/-9   
CHANGELOG.md
Documented new REST-API commands and property changes       
+4/-0     

koppor added 16 commits January 14, 2026 12:03
Technical specification completed and saved to `.zenflow/tasks/new-task-b2ce/spec.md`. The spec includes:

**Key Findings:**
- **Difficulty**: Medium
- **Architecture**: HTTP commands use Jackson polymorphic deserialization, delegate to `UiCommand` records, which are processed by `UiMessageHandler`
- **Implementation**: Create 3 new command classes mirroring CLI functionality

**Critical Dependencies:**
- `UiMessageHandler` must be registered in HK2 `ServiceLocator`
- Commands need `Platform.runLater()` for JavaFX thread safety

**Open Questions:**
1. ServiceLocator binding configuration location
2. Thread safety approach (async execution)
I'll start by reading the specification and understanding the existing code structure.
…tiple ones)

- remove libraryId and entryIds for select entries command (unsure if it is still used)
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jan 14, 2026

Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🔴
Path traversal vulnerability

Description: The OpenLibrariesCommand accepts arbitrary file paths from HTTP requests without
validation, allowing attackers to potentially access sensitive files outside intended
directories through path traversal attacks (e.g., ../../etc/passwd).
OpenLibrariesCommand.java [21-23]

Referred Code
List<Path> pathList = paths.stream()
                           .map(Path::of)
                           .toList();
Missing authentication for commands

Description: UI commands from potentially untrusted sources (HTTP server) are executed on the JavaFX
application thread without authentication or authorization checks, allowing remote
attackers to manipulate the UI and potentially access sensitive data.
JabRefFrame.java [697-702]

Referred Code
Platform.runLater(() -> {
    if (uiCommands.stream().anyMatch(UiCommand.Focus.class::isInstance)) {
        mainStage.toFront();
    }
    viewModel.handleUiCommands(uiCommands);
});
Unvalidated BibTeX injection

Description: The addBibtex endpoint accepts arbitrary BibTeX content without validation or
sanitization, potentially allowing injection of malicious code or data that could be
executed when the library is processed or displayed.
EntriesResource.java [50-59]

Referred Code
@Consumes(MediaTypes.APPLICATION_BIBTEX)
public void addBibtex(@PathParam("id") String id, String bibtex) {
    if (uiMessageHandler == null) {
        throw new BadRequestException("Only possible in GUI mode.");
    }
    if (!"current".equals(id)) {
        throw new BadRequestException("Only currently selected library possible");
    }
    uiMessageHandler.handleUiCommands(List.of(new UiCommand.AppendBibTeXToCurrentLibrary(bibtex)));
}
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Exception details exposed: The error handler returns e.getMessage() directly to the client, potentially exposing
internal implementation details or stack trace information.

Referred Code
    return Response.serverError().entity(e.getMessage()).build();
}

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Missing input validation: The bibtex parameter is accepted without validation or sanitization before being passed to
AppendBibTeXToCurrentLibrary, potentially allowing malicious BibTeX content injection.

Referred Code
public void addBibtex(@PathParam("id") String id, String bibtex) {
    if (uiMessageHandler == null) {
        throw new BadRequestException("Only possible in GUI mode.");
    }
    if (!"current".equals(id)) {
        throw new BadRequestException("Only currently selected library possible");
    }
    uiMessageHandler.handleUiCommands(List.of(new UiCommand.AppendBibTeXToCurrentLibrary(bibtex)));

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Missing null check: The code accesses citationKeyOptional.get() without verifying the Optional is present,
which could throw NoSuchElementException if the Optional is empty.

Referred Code
String citationKey = citationKeyOptional.get();
if (!keysToSelect.contains(citationKey)) {

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jan 14, 2026

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix incorrect tab selection logic
Suggestion Impact:The commit directly implements the suggested fix by changing line 5 from `if (firstFoundTab != null)` to `if (firstFoundTab == null)`, correcting the logic bug that prevented firstFoundTab from being assigned.

code diff:

-                if (firstFoundTab != null) {
+                if (firstFoundTab == null) {

Fix the condition for setting firstFoundTab from if (firstFoundTab != null) to
if (firstFoundTab == null) to correctly focus the UI on the first tab with a
found entry.

jabgui/src/main/java/org/jabref/gui/frame/JabRefFrameViewModel.java [383-420]

 @NullMarked
 private void selectEntries(List<String> entryKeys) {
     // check current library tab first
     LibraryTab currentLibraryTab = tabContainer.getCurrentLibraryTab();
     List<LibraryTab> sortedTabs = tabContainer.getLibraryTabs().stream()
                                               .sorted(Comparator.comparing(tab -> tab != currentLibraryTab))
                                               .toList();
     Set<String> keysToSelect = new HashSet<>(entryKeys);
     LibraryTab firstFoundTab = null;
     for (LibraryTab libraryTab : sortedTabs) {
         List<BibEntry> entrysToSelectInCurrentTab = new ArrayList<>(keysToSelect.size());
         for (BibEntry entry : libraryTab.getDatabase()
                                         .getEntries()) {
             Optional<String> citationKeyOptional = entry.getCitationKey();
             if (citationKeyOptional.isEmpty()) {
                 continue;
             }
             String citationKey = citationKeyOptional.get();
             if (!keysToSelect.contains(citationKey)) {
                 continue;
             }
-            if (firstFoundTab != null) {
+            if (firstFoundTab == null) {
                 firstFoundTab = libraryTab;
             }
             LOGGER.debug("Found entry {} in library tab {}", citationKey, libraryTab);
             keysToSelect.remove(citationKey);
             entrysToSelectInCurrentTab.add(entry);
         }
         libraryTab.clearAndSelect(entrysToSelectInCurrentTab);
     }
     LOGGER.trace("End of loop");
     if (firstFoundTab != null) {
         tabContainer.showLibraryTab(firstFoundTab);
     }
     for (String key : keysToSelect) {
         dialogService.notify(Localization.lang("Citation key '%0' to select not found in open libraries.", key));
     }
 }

[Suggestion processed]

Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a logical bug in the new selectEntries method where firstFoundTab is never assigned, preventing the UI from focusing on the correct tab.

High
General
Validate for empty BibTeX data
Suggestion Impact:The suggestion was directly implemented in the commit. The exact validation check suggested (checking if bibtex is null or blank and throwing a BadRequestException with the message "BibTeX data must not be empty.") was added to the addBibtex method at the recommended location.

code diff:

+        if (bibtex == null || bibtex.isBlank()) {
+            throw new BadRequestException("BibTeX data must not be empty.");
+        }

Add a validation check in the addBibtex method to ensure the bibtex string is
not null or blank, throwing a BadRequestException if it is.

jabsrv/src/main/java/org/jabref/http/server/resources/EntriesResource.java [49-59]

 @POST
 @Consumes(MediaTypes.APPLICATION_BIBTEX)
 public void addBibtex(@PathParam("id") String id, String bibtex) {
     if (uiMessageHandler == null) {
         throw new BadRequestException("Only possible in GUI mode.");
     }
     if (!"current".equals(id)) {
         throw new BadRequestException("Only currently selected library possible");
     }
+    if (bibtex == null || bibtex.isBlank()) {
+        throw new BadRequestException("BibTeX data must not be empty.");
+    }
     uiMessageHandler.handleUiCommands(List.of(new UiCommand.AppendBibTeXToCurrentLibrary(bibtex)));
 }

[Suggestion processed]

Suggestion importance[1-10]: 6

__

Why: The suggestion correctly points out missing input validation for the bibtex string, which improves the robustness of the new API endpoint by handling empty requests gracefully.

Low
Learned
best practice
Fix typos in changelog
Suggestion Impact:The commit directly implements both typo fixes suggested: line 11 changes "More added more commands" to "Added more commands", and line 12 changes "import dialogg" to "import dialog"

code diff:

+- REST-API: Added more commands (`selectentries`, `open`, `focus`).
+- REST-API: Added the possibility to trigger the import dialog

Fix the typographical errors: "More added more" should be "Added more" and
"dialogg" should be "dialog".

CHANGELOG.md [18-19]

-- REST-API: More added more commands (`selectentries`, `open`, `focus`).
-- REST-API: Added the possibility to trigger the import dialogg
+- REST-API: Added more commands (`selectentries`, `open`, `focus`).
+- REST-API: Added the possibility to trigger the import dialog

[Suggestion processed]

Suggestion importance[1-10]: 5

__

Why:
Relevant best practice - Correct typographical errors in documentation, code comments, configuration files, and user-facing strings. This includes fixing misspellings in variable names, method names, documentation text, changelog entries, and localization strings to maintain code quality and professionalism.

Low
  • Update

@github-actions github-actions Bot added the status: changes-required Pull requests that are not yet complete label Jan 14, 2026
Comment thread CHANGELOG.md Outdated
koppor and others added 3 commits January 14, 2026 23:26
Co-authored-by: qodo-free-for-open-source-projects[bot] <189517486+qodo-free-for-open-source-projects[bot]@users.noreply.github.com>
@github-actions github-actions Bot removed the status: changes-required Pull requests that are not yet complete label Jan 14, 2026
@github-actions github-actions Bot added the status: changes-required Pull requests that are not yet complete label Jan 14, 2026
@github-actions github-actions Bot removed the status: changes-required Pull requests that are not yet complete label Jan 14, 2026
Comment thread CHANGELOG.md

### Changed

- REST-API: Command resource: `command` instead of `commandId`. [#14855](https://github.com/JabRef/jabref/pull/14855)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If we change this, we probably should adapt jabmap, shouldn't we?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could also add an alias and adapt jabmap later on and than remove the alias again

private ServiceLocator serviceLocator;
// TODO: This is probably needed for some CAYW functionality to "scope" the citation keys properly
// @JsonProperty
// private String libraryId = "";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is not for cayw but for jabmap if I remember correctly.

}
// TODO: This is probably needed for some CAYW functionality to use a unique entry id "scope" the citation keys properly
// @JsonProperty
// private List<String> entryIds = new ArrayList<>();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here

}

if (filesToServe.isEmpty()) {
// empty filesToServe indicates GUI mode

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could also check if srvStateManager instanceOf JabRevSrvStateManager this should be more reliable, but i also dont see a downside of this check

@github-actions github-actions Bot added the status: changes-required Pull requests that are not yet complete label Jan 14, 2026
@github-actions github-actions Bot removed the status: changes-required Pull requests that are not yet complete label Jan 15, 2026
@koppor koppor enabled auto-merge January 15, 2026 00:07
@koppor koppor added this pull request to the merge queue Jan 15, 2026
Merged via the queue into JabRef:main with commit 79ffeae Jan 15, 2026
50 checks passed
@koppor koppor deleted the new-task-b2ce branch January 15, 2026 01:02
Siedlerchr added a commit to st-rm-ng/jabref that referenced this pull request Jan 17, 2026
* upstream/main: (64 commits)
  New Crowdin updates (JabRef#14862)
  Make JDK25 available (JabRef#14861)
  Fix empty entries array when exporting group chat to JSON (JabRef#14814)
  feat: add right-click copy context menu to AI chat messages (JabRef#14722)
  FIX : generic error dialog and icon in Source Tab parsing (JabRef#14828)
  Factor out setup-* actions (JabRef#14859)
  Link .http files.
  Update dependency org.postgresql:postgresql to v42.7.9 (JabRef#14857)
  Add more commands to JabSrv (JabRef#14855)
  Fix JabRef#14821: Hide identifier action buttons when field is empty (JabRef#14831)
  Add GH_TOKEN to closed issues/PRs processing step
  New Crowdin updates (JabRef#14854)
  New Crowdin updates (JabRef#14849)
  Chore(deps): Bump jablib/src/main/resources/csl-styles from `0201999` to `f345aa8` (JabRef#14833)
  Add support for book front covers, again (JabRef#14777)
  Readd min width to button in new enty dialog (JabRef#14791)
  Replace plugin impl from jbang plugin (JabRef#14846)
  Revise AI policy wording
  Chore(deps): Bump jablib/src/main/resources/csl-locales (JabRef#14677)
  Update dependency com.konghq:unirest-modules-gson to v4.7.1 (JabRef#14845)
  ...
@koppor koppor mentioned this pull request Jan 20, 2026
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants