Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions jabsrv/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
exports org.jabref.http.dto to com.google.gson, org.glassfish.hk2.locator;
exports org.jabref.http.dto.cayw to com.google.gson;

opens org.jabref.http.server to org.glassfish.hk2.utilities, org.glassfish.hk2.locator;
opens org.jabref.http.dto to com.google.gson;
opens org.jabref.http.server to com.google.gson, org.glassfish.hk2.utilities, org.glassfish.hk2.locator;
opens org.jabref.http.server.cayw to com.google.gson, org.glassfish.hk2.locator, org.glassfish.hk2.utilities;
exports org.jabref.http.server.cayw to jersey.server;
opens org.jabref.http.server.command to , com.fasterxml.jackson.databind, com.google.gson, org.glassfish.hk2.locator, org.glassfish.hk2.utilities;
exports org.jabref.http.server.command to jersey.server;
opens org.jabref.http.server.cayw to com.google.gson, org.glassfish.hk2.locator, org.glassfish.hk2.utilities;
opens org.jabref.http.dto to com.google.gson;
opens org.jabref.http.server.command to com.google.gson, org.glassfish.hk2.locator, org.glassfish.hk2.utilities, com.fasterxml.jackson.databind;

exports org.jabref.http.server.services;
exports org.jabref.http;

Expand Down
19 changes: 19 additions & 0 deletions jabsrv/src/main/java/org/jabref/http/dto/AddEntryDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.jabref.http.dto;

public class AddEntryDTO {
private String text;

public AddEntryDTO() {}

public AddEntryDTO(String text) {
this.text = text;
}

public String getText() {
return text;
}

public void setText(String text) {
this.text = text;
}
}
123 changes: 123 additions & 0 deletions jabsrv/src/main/java/org/jabref/http/server/LatestLibraryResource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package org.jabref.http.server;

import java.util.Optional;

import org.jabref.http.SrvStateManager;
import org.jabref.http.dto.AddEntryDTO;
import org.jabref.http.dto.BibEntryDTO;
import org.jabref.http.server.services.FilesToServe;
import org.jabref.logic.importer.ParseException;
import org.jabref.logic.importer.fileformat.BibtexParser;
import org.jabref.logic.preferences.CliPreferences;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.entry.event.EntriesEventSource;

import com.airhacks.afterburner.injection.Injector;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import jakarta.inject.Inject;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Path("libraries/latest")
Copy link
Member

Choose a reason for hiding this comment

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

I think, this won't work...

REST works differently... a) redirect to path where this is stored -- I don't know how the client works or b) direct handling in LibraryResource.

Conflicts with @Path("libraries/{id}") at libraries

REST background: ROA -> https://en.wikipedia.org/wiki/Resource-oriented_architecture - everything is a resource, not a command endpoint (if possible)

i will dive into later

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

Well, ideal:

  1. Fetch /libraries?sort_by=date&sort_direction=desc
  2. /libraries/#{libraries[0].id}

public class LatestLibraryResource {

private static final Logger LOGGER = LoggerFactory.getLogger(LatestLibraryResource.class);

@Inject
private SrvStateManager srvStateManager;

@Inject
private FilesToServe filesToServe;

@Inject
private CliPreferences preferences;

@Inject
private Gson gson;

@POST
@Path("entries")
public Response addEntry(String jsonInput) {
// Manual JSON parsing with gson.fromJson
AddEntryDTO request;
try {
if (jsonInput == null || jsonInput.trim().isEmpty()) {
Comment on lines +50 to +51
Copy link

Choose a reason for hiding this comment

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

The try block covers too many statements, which can make it harder to identify which specific statement caused an exception.

return Response.status(Response.Status.BAD_REQUEST)
.entity(gson.toJson(new ErrorResponse("Missing JSON input")))
.type(MediaType.APPLICATION_JSON)
.build();
}

request = gson.fromJson(jsonInput, AddEntryDTO.class);
} catch (JsonSyntaxException e) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(gson.toJson(new ErrorResponse("Invalid JSON format: " + e.getMessage())))
.type(MediaType.APPLICATION_JSON)
.build();
}

if (request == null || request.getText() == null || request.getText().trim().isEmpty()) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(gson.toJson(new ErrorResponse("Missing or empty 'text' field")))
.type(MediaType.APPLICATION_JSON)
.build();
}

Optional<BibDatabaseContext> activeDb = srvStateManager.getActiveDatabase();
if (activeDb.isEmpty()) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(gson.toJson(new ErrorResponse("No active library. Please open a library first.")))
.type(MediaType.APPLICATION_JSON)
.build();
}

String bibtexSource = request.getText();

BibtexParser parser = new BibtexParser(preferences.getImportFormatPreferences());

try {
Optional<BibEntry> entry = parser.parseSingleEntry(bibtexSource);
if (entry.isEmpty()) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(gson.toJson(new ErrorResponse("No valid BibTeX entry found")))
.type(MediaType.APPLICATION_JSON)
.build();
}

activeDb.get().getDatabase().insertEntry(entry.get(), EntriesEventSource.SHARED);

BibEntryTypesManager entryTypesManager = Injector.instantiateModelOrService(BibEntryTypesManager.class);
BibEntryDTO dto = new BibEntryDTO(entry.get(), activeDb.get().getMode(), preferences.getFieldPreferences(), entryTypesManager);

// Manual JSON serialization with gson.toJson
return Response.ok(gson.toJson(dto))
.type(MediaType.APPLICATION_JSON)
.build();
} catch (ParseException e) {
return Response.status(Response.Status.BAD_REQUEST)
.entity(gson.toJson(new ErrorResponse("Error parsing BibTeX entry: " + e.getMessage())))
.type(MediaType.APPLICATION_JSON)
.build();
}
}

// Helper class for error responses
Copy link
Member

Choose a reason for hiding this comment

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

Use three slashes 😅

private static class ErrorResponse {
private final String error;

public ErrorResponse(String error) {
this.error = error;
}

public String getError() {
return error;
}
}
}
1 change: 1 addition & 0 deletions jabsrv/src/main/java/org/jabref/http/server/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ private HttpServer startServer(ServiceLocator serviceLocator, URI uri) {
resourceConfig.register(CommandResource.class);
resourceConfig.register(CORSFilter.class);
resourceConfig.register(GlobalExceptionMapper.class);
resourceConfig.register(LatestLibraryResource.class);

LOGGER.debug("Starting HTTP server...");
final HttpServer httpServer =
Expand Down
Loading