Skip to content
Closed
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
98 changes: 98 additions & 0 deletions jabsrv/src/main/java/org/jabref/http/server/BibEntryResource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package org.jabref.http.server;

import java.io.IOException;
import java.util.List;

import org.jabref.http.JabrefMediaType;
import org.jabref.http.SrvStateManager;
import org.jabref.http.dto.BibEntryDTO;
import org.jabref.http.server.services.FilesToServe;
import org.jabref.http.server.services.ServerUtils;
import org.jabref.logic.citationstyle.JabRefItemDataProvider;
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 com.airhacks.afterburner.injection.Injector;
import com.google.gson.Gson;
import de.undercouch.citeproc.csl.CSLItemData;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Path("libraries/{id}/entries/{entryId}")
public class BibEntryResource {

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

@Inject
private CliPreferences preferences;

@Inject
private SrvStateManager srvStateManager;

@Inject
private FilesToServe filesToServe;

@Inject
private Gson gson;

@GET
@Produces(JabrefMediaType.JSON_CSL_ITEM)
public String getCSLJsonRepresentation(@PathParam("id") String id,
@PathParam("entryId") String entryId) throws IOException {
List<BibEntry> entriesByCitationKey = getDatabaseContext(id)
.getDatabase()
.getEntriesByCitationKey(entryId);

if (entriesByCitationKey.isEmpty()) {
throw new NotFoundException("Entry with citation key '" + entryId + "' not found in library " + id);
}

if (entriesByCitationKey.size() > 1) {
LOGGER.warn("Multiple CSL JSON entries found with citation key '{}'. Using the first one.", entryId);
}

BibEntryTypesManager entryTypesManager = Injector.instantiateModelOrService(BibEntryTypesManager.class);
JabRefItemDataProvider jabRefItemDataProvider = new JabRefItemDataProvider();
jabRefItemDataProvider.setData(entriesByCitationKey, getDatabaseContext(id), entryTypesManager);

CSLItemData cslItem = jabRefItemDataProvider.retrieveItem(entryId);

if (cslItem == null) {
throw new NotFoundException("Unable to convert entry '" + entryId + "' to CSL JSON");
}

return gson.toJson(List.of(cslItem));
}

@GET
@Produces(MediaType.APPLICATION_JSON)
public String getJsonRepresentation(@PathParam("id") String id,
@PathParam("entryId") String entryId) throws IOException {
BibDatabaseContext databaseContextBib = getDatabaseContext(id);
BibEntryTypesManager entryTypesManager = Injector.instantiateModelOrService(BibEntryTypesManager.class);

List<BibEntryDTO> list = databaseContextBib.getDatabase()
.getEntriesByCitationKey(entryId)
.stream()
.map(entry -> new BibEntryDTO(entry,
databaseContextBib.getMode(),
preferences.getFieldPreferences(),
entryTypesManager))
.toList();

return gson.toJson(list);
}

private BibDatabaseContext getDatabaseContext(String id) throws IOException {
return ServerUtils.getBibDatabaseContext(id, filesToServe, srvStateManager, preferences.getImportFormatPreferences());
}
}
103 changes: 4 additions & 99 deletions jabsrv/src/main/java/org/jabref/http/server/LibraryResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.BibEntryTypesManager;
import org.jabref.model.entry.LinkedFile;
import org.jabref.model.entry.field.StandardField;

import com.airhacks.afterburner.injection.Injector;
import com.google.gson.Gson;
Expand All @@ -45,16 +44,16 @@ public class LibraryResource {
private static final Logger LOGGER = LoggerFactory.getLogger(LibraryResource.class);

@Inject
CliPreferences preferences;
private CliPreferences preferences;

@Inject
SrvStateManager srvStateManager;
private SrvStateManager srvStateManager;

@Inject
FilesToServe filesToServe;
private FilesToServe filesToServe;

@Inject
Gson gson;
private Gson gson;

/**
* At http://localhost:23119/libraries/{id}
Expand Down Expand Up @@ -202,101 +201,7 @@ private BibDatabaseContext getDatabaseContext(String id) throws IOException {
return ServerUtils.getBibDatabaseContext(id, filesToServe, srvStateManager, preferences.getImportFormatPreferences());
}

/**
* At http://localhost:23119/libraries/{id}/entries/{entryId} <br><br>
*
* Combines attributes of a given BibEntry into a basic entry preview for as plain text.
*
* @param id The name of the library
* @param entryId The CitationKey of the BibEntry
* @return a basic entry preview as plain text
* @throws IOException
* @throws NotFoundException
*/
@GET
@Path("entries/{entryId}")
@Produces(MediaType.TEXT_PLAIN + ";charset=UTF-8")
public String getPlainRepresentation(@PathParam("id") String id, @PathParam("entryId") String entryId) throws IOException {
BibDatabaseContext databaseContext = getDatabaseContext(id);
List<BibEntry> entriesByCitationKey = databaseContext.getDatabase().getEntriesByCitationKey(entryId);
if (entriesByCitationKey.isEmpty()) {
throw new NotFoundException("Entry with citation key '" + entryId + "' not found in library " + id);
}
if (entriesByCitationKey.size() > 1) {
LOGGER.warn("Multiple entries found with citation key '{}'. Using the first one.", entryId);
}

// TODO: Currently, the preview preferences are in GUI package, which is not accessible here.
// build the preview
BibEntry entry = entriesByCitationKey.getFirst();

String author = entry.getField(StandardField.AUTHOR).orElse("(N/A)");
String title = entry.getField(StandardField.TITLE).orElse("(N/A)");
String journal = entry.getField(StandardField.JOURNAL).orElse("(N/A)");
String volume = entry.getField(StandardField.VOLUME).orElse("(N/A)");
String number = entry.getField(StandardField.NUMBER).orElse("(N/A)");
String pages = entry.getField(StandardField.PAGES).orElse("(N/A)");
String releaseDate = entry.getField(StandardField.DATE).orElse("(N/A)");

// the only difference to the HTML version of this method is the format of the output:
String preview =
"Author: " + author
+ "\nTitle: " + title
+ "\nJournal: " + journal
+ "\nVolume: " + volume
+ "\nNumber: " + number
+ "\nPages: " + pages
+ "\nReleased on: " + releaseDate;

return preview;
}
Comment on lines -205 to -252
Copy link
Member

Choose a reason for hiding this comment

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

Those are the ones that should be moved to the new resource.


/**
* At http://localhost:23119/libraries/{id}/entries/{entryId} <br><br>
*
* Combines attributes of a given BibEntry into a basic entry preview for as HTML text.
*
* @param id The name of the library
* @param entryId The CitationKey of the BibEntry
* @return a basic entry preview as HTML text
* @throws IOException
*/
@GET
@Path("entries/{entryId}")
@Produces(MediaType.TEXT_HTML + ";charset=UTF-8")
public String getHTMLRepresentation(@PathParam("id") String id, @PathParam("entryId") String entryId) throws IOException {
List<BibEntry> entriesByCitationKey = getDatabaseContext(id).getDatabase().getEntriesByCitationKey(entryId);
if (entriesByCitationKey.isEmpty()) {
throw new NotFoundException("Entry with citation key '" + entryId + "' not found in library " + id);
}
if (entriesByCitationKey.size() > 1) {
LOGGER.warn("Multiple entries found with citation key '{}'. Using the first one.", entryId);
}

// TODO: Currently, the preview preferences are in GUI package, which is not accessible here.
// build the preview
BibEntry entry = entriesByCitationKey.getFirst();

String author = entry.getField(StandardField.AUTHOR).orElse("(N/A)");
String title = entry.getField(StandardField.TITLE).orElse("(N/A)");
String journal = entry.getField(StandardField.JOURNAL).orElse("(N/A)");
String volume = entry.getField(StandardField.VOLUME).orElse("(N/A)");
String number = entry.getField(StandardField.NUMBER).orElse("(N/A)");
String pages = entry.getField(StandardField.PAGES).orElse("(N/A)");
String releaseDate = entry.getField(StandardField.DATE).orElse("(N/A)");

// the only difference to the plain text version of this method is the format of the output:
String preview =
"<strong>Author:</strong> " + author + "<br>" +
"<strong>Title:</strong> " + title + "<br>" +
"<strong>Journal:</strong> " + journal + "<br>" +
"<strong>Volume:</strong> " + volume + "<br>" +
"<strong>Number:</strong> " + number + "<br>" +
"<strong>Pages:</strong> " + pages + "<br>" +
"<strong>Released on:</strong> " + releaseDate;

return preview;
}
Comment on lines -254 to -299
Copy link
Member

Choose a reason for hiding this comment

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

those too


/**
* At http://localhost:23119/libraries/{id}/entries/pdffiles <br><br>
Expand Down
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(BibEntryResource.class);

LOGGER.debug("Starting HTTP server...");
final HttpServer httpServer =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package org.jabref.http.server;

import org.jabref.http.JabrefMediaType;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.MediaType;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class BibEntryResourceTest extends ServerTest {


private final ObjectMapper mapper = new ObjectMapper();

@Override
protected Application configure() {
ResourceConfig resourceConfig = new ResourceConfig(
LibraryResource.class,
LibrariesResource.class,
BibEntryResource.class
);
addFilesToServeToResourceConfig(resourceConfig);
addGuiBridgeToResourceConfig(resourceConfig);
addPreferencesToResourceConfig(resourceConfig);
addGsonToResourceConfig(resourceConfig);
return resourceConfig.getApplication();
}

@Test
void getCSLJsonRepresentation() throws Exception {
String response = target("/libraries/" + TestBibFile.GENERAL_SERVER_TEST.id + "/entries/Author2023test")
.request(JabrefMediaType.JSON_CSL_ITEM)
.get(String.class);
String expected = """
[
{
"id": "Author2023test",
"type": "ARTICLE",
"author": [
{
"family": "Author",
"given": "Demo"
}
],
"eventDate": {
"dateParts": [
[
2023
]
]
},
"issued": {
"dateParts": [
[
2023
]
]
},
"title": "Demo Title"
}
]
""";

JsonNode root = mapper.readTree(response);
JsonNode expectedJson = mapper.readTree(expected);

assertEquals(root, expectedJson, "CSL JSON must match the expected structure");
}

@Test
void getJsonRepresentation() throws Exception {
String response = target("/libraries/" + TestBibFile.GENERAL_SERVER_TEST.id + "/entries/Author2023test")
.request(MediaType.APPLICATION_JSON)
.get(String.class);
String expected = """
[
{
"sharingMetadata": {
"sharedID": -1,
"version": 1
},
"userComments": "",
"citationKey": "Author2023test",
"bibtex": "@Misc{Author2023test,\\n author \\u003d {Demo Author},\\n title \\u003d {Demo Title},\\n year \\u003d {2023},\\n}\\n"
}
]
""";

JsonNode root = mapper.readTree(response);

JsonNode expectedJson = mapper.readTree(expected);

assertEquals(root, expectedJson, "JSON must match the expected structure");
}
}
3 changes: 3 additions & 0 deletions jabsrv/src/test/rest-api.http
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,6 @@ Accept: application/x-bibtex-library-csl+json
### GET not available library

GET http://localhost:23119/libraries/notfound

###
GET http://localhost:23119/libraries/demo/entries/Corti_2009
Comment on lines +97 to +99
Copy link
Member

Choose a reason for hiding this comment

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

Please add a heading like on the others and move it up to the other cases which handle the entries itself, the end is for error cases. Also add that it only accepts the according mediatype

Loading