Skip to content

Commit 34c25e0

Browse files
authored
Hotfix: Add support for ids in CAYW resource (#13471)
* Hotfix for CAYW in GUI * Add support for library ids in CAYW * Reformat code * Try to have focus * Add demo to cayw.http * OpenRewrite
1 parent ed6bf99 commit 34c25e0

File tree

7 files changed

+143
-63
lines changed

7 files changed

+143
-63
lines changed

jabsrv/src/main/java/org/jabref/http/server/LibraryResource.java

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,27 @@
11
package org.jabref.http.server;
22

3-
import java.io.BufferedReader;
43
import java.io.IOException;
54
import java.io.InputStream;
6-
import java.io.InputStreamReader;
7-
import java.nio.charset.StandardCharsets;
85
import java.nio.file.Files;
96
import java.util.List;
107
import java.util.Objects;
11-
import java.util.Optional;
128

139
import org.jabref.http.JabrefMediaType;
1410
import org.jabref.http.dto.BibEntryDTO;
1511
import org.jabref.http.server.services.ContextsToServe;
1612
import org.jabref.http.server.services.FilesToServe;
13+
import org.jabref.http.server.services.ServerUtils;
1714
import org.jabref.logic.citationstyle.JabRefItemDataProvider;
18-
import org.jabref.logic.importer.ParserResult;
19-
import org.jabref.logic.importer.fileformat.BibtexImporter;
2015
import org.jabref.logic.preferences.CliPreferences;
21-
import org.jabref.logic.util.io.BackupFileUtil;
2216
import org.jabref.model.database.BibDatabase;
2317
import org.jabref.model.database.BibDatabaseContext;
2418
import org.jabref.model.entry.BibEntryTypesManager;
25-
import org.jabref.model.util.DummyFileUpdateMonitor;
2619

2720
import com.airhacks.afterburner.injection.Injector;
2821
import com.google.gson.Gson;
2922
import jakarta.inject.Inject;
3023
import jakarta.ws.rs.GET;
3124
import jakarta.ws.rs.InternalServerErrorException;
32-
import jakarta.ws.rs.NotFoundException;
3325
import jakarta.ws.rs.Path;
3426
import jakarta.ws.rs.PathParam;
3527
import jakarta.ws.rs.Produces;
@@ -93,7 +85,7 @@ public Response getBibtex(@PathParam("id") String id) {
9385
.build();
9486
}
9587

96-
java.nio.file.Path library = getLibraryPath(id);
88+
java.nio.file.Path library = ServerUtils.getLibraryPath(id, filesToServe, contextsToServe);
9789
String libraryAsString;
9890
try {
9991
libraryAsString = Files.readString(library);
@@ -107,41 +99,9 @@ public Response getBibtex(@PathParam("id") String id) {
10799
.build();
108100
}
109101

110-
private java.nio.file.Path getLibraryPath(String id) {
111-
return filesToServe.getFilesToServe()
112-
.stream()
113-
.filter(p -> (p.getFileName() + "-" + BackupFileUtil.getUniqueFilePrefix(p)).equals(id))
114-
.findAny()
115-
.orElseThrow(NotFoundException::new);
116-
}
117-
102+
/// @param id - also "demo" for the Chocolate.bib file
118103
private BibDatabaseContext getDatabaseContext(String id) throws IOException {
119-
BibtexImporter bibtexImporter = new BibtexImporter(preferences.getImportFormatPreferences(), new DummyFileUpdateMonitor());
120-
121-
if ("demo".equals(id)) {
122-
try (InputStream chocolateBibInputStream = getChocolateBibAsStream()) {
123-
BufferedReader reader = new BufferedReader(new InputStreamReader(chocolateBibInputStream, StandardCharsets.UTF_8));
124-
return bibtexImporter.importDatabase(reader).getDatabaseContext();
125-
}
126-
}
127-
128-
java.nio.file.Path library = getLibraryPath(id);
129-
if (!filesToServe.isEmpty()) {
130-
ParserResult parserResult;
131-
try {
132-
parserResult = bibtexImporter.importDatabase(library);
133-
} catch (IOException e) {
134-
LOGGER.warn("Could not find open library file {}", library, e);
135-
throw new InternalServerErrorException("Could not parse library", e);
136-
}
137-
return parserResult.getDatabaseContext();
138-
}
139-
140-
// contextsToServe.isEmpty() could be true when no libraries are opened in JabRef
141-
return contextsToServe.getContextsToServe().stream()
142-
.filter(context -> context.getDatabasePath().equals(Optional.of(library)))
143-
.findFirst()
144-
.orElseThrow(() -> new NotFoundException("No library with id " + id + " found"));
104+
return ServerUtils.getBibDatabaseContext(id, filesToServe, contextsToServe, preferences.getImportFormatPreferences());
145105
}
146106

147107
/// @return a stream to the Chocolate.bib file in the classpath (is null only if the file was moved or there are issues with the classpath)

jabsrv/src/main/java/org/jabref/http/server/cayw/CAYWQueryParams.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ public class CAYWQueryParams {
3838
@QueryParam("librarypath")
3939
private String libraryPath;
4040

41+
@QueryParam("libraryid")
42+
private String libraryId;
43+
4144
public String getCommand() {
4245
return command;
4346
}
@@ -73,4 +76,8 @@ public String getFormat() {
7376
public Optional<String> getLibraryPath() {
7477
return Optional.ofNullable(libraryPath);
7578
}
79+
80+
public Optional<String> getLibraryId() {
81+
return Optional.ofNullable(libraryId);
82+
}
7683
}

jabsrv/src/main/java/org/jabref/http/server/cayw/CAYWResource.java

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.nio.file.Files;
1212
import java.util.ArrayList;
1313
import java.util.List;
14+
import java.util.Optional;
1415
import java.util.concurrent.CompletableFuture;
1516
import java.util.concurrent.CountDownLatch;
1617
import java.util.concurrent.ExecutionException;
@@ -22,6 +23,8 @@
2223
import org.jabref.http.server.cayw.gui.CAYWEntry;
2324
import org.jabref.http.server.cayw.gui.SearchDialog;
2425
import org.jabref.http.server.services.ContextsToServe;
26+
import org.jabref.http.server.services.FilesToServe;
27+
import org.jabref.http.server.services.ServerUtils;
2528
import org.jabref.logic.importer.fileformat.BibtexImporter;
2629
import org.jabref.logic.preferences.CliPreferences;
2730
import org.jabref.model.database.BibDatabase;
@@ -54,6 +57,9 @@ public class CAYWResource {
5457
@Inject
5558
private FormatterService formatterService;
5659

60+
@Inject
61+
private FilesToServe filesToServe;
62+
5763
@Inject
5864
private ContextsToServe contextsToServe;
5965

@@ -66,17 +72,7 @@ public Response getCitation(
6672
return Response.ok("ready").build();
6773
}
6874

69-
BibDatabaseContext databaseContext;
70-
71-
// handle library path parameter
72-
if (queryParams.getLibraryPath().isPresent() && "demo".equalsIgnoreCase(queryParams.getLibraryPath().get())) {
73-
databaseContext = getDatabaseContextFromStream(getChocolateBibAsStream());
74-
} else if (queryParams.getLibraryPath().isPresent()) {
75-
InputStream inputStream = getDatabaseStreamFromPath(java.nio.file.Path.of(queryParams.getLibraryPath().get()));
76-
databaseContext = getDatabaseContextFromStream(inputStream);
77-
} else {
78-
databaseContext = getDatabaseContextFromStream(getLatestDatabaseStream());
79-
}
75+
BibDatabaseContext databaseContext = getBibDatabaseContext(queryParams);
8076

8177
/* unused until DatabaseSearcher is fixed
8278
PostgreServer postgreServer = new PostgreServer();
@@ -97,14 +93,15 @@ public Response getCitation(
9793

9894
CompletableFuture<List<CAYWEntry>> future = new CompletableFuture<>();
9995
Platform.runLater(() -> {
100-
SearchDialog dialog = new SearchDialog();
101-
// TODO: Using the DatabaseSearcher directly here results in a lot of exceptions being thrown, so we use an alternative for now until we have a nice way of using the DatabaseSearcher class.
102-
// searchDialog.set(new SearchDialog<>(s -> searcher.getMatches(new SearchQuery(s)), entries));
103-
List<CAYWEntry> results = dialog.show(searchQuery ->
104-
entries.stream().filter(caywEntry -> matches(caywEntry, searchQuery)).toList(),
96+
SearchDialog dialog = new SearchDialog();
97+
// TODO: Using the DatabaseSearcher directly here results in a lot of exceptions being thrown, so we use an alternative for now until we have a nice way of using the DatabaseSearcher class.
98+
// searchDialog.set(new SearchDialog<>(s -> searcher.getMatches(new SearchQuery(s)), entries));
99+
List<CAYWEntry> results = dialog.show(
100+
searchQuery ->
101+
entries.stream()
102+
.filter(caywEntry -> matches(caywEntry, searchQuery)).toList(),
105103
entries);
106-
107-
future.complete(results);
104+
future.complete(results);
108105
});
109106

110107
List<CAYWEntry> searchResults = future.get();
@@ -127,6 +124,29 @@ public Response getCitation(
127124
return Response.ok(response).build();
128125
}
129126

127+
private BibDatabaseContext getBibDatabaseContext(CAYWQueryParams queryParams) throws IOException {
128+
Optional<String> libraryId = queryParams.getLibraryId();
129+
if (libraryId.isPresent()) {
130+
if ("demo".equals(libraryId.get())) {
131+
return ServerUtils.getBibDatabaseContext("demo", filesToServe, contextsToServe, preferences.getImportFormatPreferences());
132+
}
133+
return ServerUtils.getBibDatabaseContext(libraryId.get(), filesToServe, contextsToServe, preferences.getImportFormatPreferences());
134+
}
135+
136+
Optional<String> libraryPath = queryParams.getLibraryPath();
137+
if (libraryPath.isPresent() && "demo".equals(libraryPath.get())) {
138+
return ServerUtils.getBibDatabaseContext("demo", filesToServe, contextsToServe, preferences.getImportFormatPreferences());
139+
}
140+
141+
if (queryParams.getLibraryPath().isPresent()) {
142+
assert !"demo".equalsIgnoreCase(queryParams.getLibraryPath().get());
143+
InputStream inputStream = getDatabaseStreamFromPath(java.nio.file.Path.of(queryParams.getLibraryPath().get()));
144+
return getDatabaseContextFromStream(inputStream);
145+
}
146+
147+
return getDatabaseContextFromStream(getLatestDatabaseStream());
148+
}
149+
130150
private InputStream getLatestDatabaseStream() throws IOException {
131151
InputStream libraryStream;
132152
// Use the latest opened library as the default library

jabsrv/src/main/java/org/jabref/http/server/cayw/gui/SearchDialog.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ public List<CAYWEntry> show(Function<String, List<CAYWEntry>> searchFunction, Li
103103
dialogStage.setX((screenBounds.getWidth() - dialogWidth) / 2);
104104
dialogStage.setY((screenBounds.getHeight() - dialogHeight) / 2);
105105

106+
// Ensure that dialog is not just flashing in the taskbar, but really in front
107+
// TODO: Investigate why this is not working
108+
// scene.getWindow().requestFocus();
109+
106110
dialogStage.showAndWait();
107111

108112
return selectedItems;

jabsrv/src/main/java/org/jabref/http/server/services/ContextsToServe.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public ObservableList<BibDatabaseContext> getContextsToServe() {
1818
return contextsToServe;
1919
}
2020

21+
/// contextsToServe.isEmpty() could be true when no libraries are opened in JabRef
22+
/// Check filesToServe.isEmpty() to determine whether called from the CLI or GUI
2123
public boolean isEmpty() {
2224
return contextsToServe == null || contextsToServe.isEmpty();
2325
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package org.jabref.http.server.services;
2+
3+
import java.io.BufferedReader;
4+
import java.io.IOException;
5+
import java.io.InputStream;
6+
import java.io.InputStreamReader;
7+
import java.nio.charset.StandardCharsets;
8+
import java.nio.file.Path;
9+
10+
import org.jabref.logic.importer.ImportFormatPreferences;
11+
import org.jabref.logic.importer.fileformat.BibtexImporter;
12+
import org.jabref.logic.util.io.BackupFileUtil;
13+
import org.jabref.model.database.BibDatabase;
14+
import org.jabref.model.database.BibDatabaseContext;
15+
import org.jabref.model.util.DummyFileUpdateMonitor;
16+
17+
import jakarta.ws.rs.InternalServerErrorException;
18+
import jakarta.ws.rs.NotFoundException;
19+
import org.jspecify.annotations.NonNull;
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
22+
23+
public class ServerUtils {
24+
private static final Logger LOGGER = LoggerFactory.getLogger(ServerUtils.class);
25+
26+
private static java.nio.file.Path getLibraryPath(String id, FilesToServe filesToServe) {
27+
return filesToServe.getFilesToServe()
28+
.stream()
29+
.filter(p -> (p.getFileName() + "-" + BackupFileUtil.getUniqueFilePrefix(p)).equals(id))
30+
.findAny()
31+
.orElseThrow(NotFoundException::new);
32+
}
33+
34+
private static java.nio.file.Path getLibraryPath(String id, ContextsToServe contextsToServe) {
35+
return contextsToServe.getContextsToServe()
36+
.stream()
37+
.filter(context -> context.getDatabasePath().isPresent())
38+
.map(context -> context.getDatabasePath().get())
39+
.filter(p -> (p.getFileName() + "-" + BackupFileUtil.getUniqueFilePrefix(p)).equals(id))
40+
.findAny()
41+
.orElseThrow(NotFoundException::new);
42+
}
43+
44+
/// @throws NotFoundException if no file with the given id is found in either filesToServe or contextsToServe
45+
public static @NonNull Path getLibraryPath(String id, FilesToServe filesToServe, ContextsToServe contextsToServe) {
46+
if (filesToServe.isEmpty()) {
47+
return getLibraryPath(id, contextsToServe);
48+
} else {
49+
return getLibraryPath(id, filesToServe);
50+
}
51+
}
52+
53+
/// @param id - also "demo" for the demo library
54+
/// @throws NotFoundException if no file with the given id is found in either filesToServe or contextsToServe
55+
public static @NonNull BibDatabaseContext getBibDatabaseContext(String id, FilesToServe filesToServe, ContextsToServe contextsToServe, ImportFormatPreferences importFormatPreferences) throws IOException {
56+
BibtexImporter bibtexImporter = new BibtexImporter(importFormatPreferences, new DummyFileUpdateMonitor());
57+
if ("demo".equals(id)) {
58+
try (InputStream chocolateBibInputStream = BibDatabase.class.getResourceAsStream("/Chocolate.bib")) {
59+
BufferedReader reader = new BufferedReader(new InputStreamReader(chocolateBibInputStream, StandardCharsets.UTF_8));
60+
return bibtexImporter.importDatabase(reader).getDatabaseContext();
61+
}
62+
}
63+
64+
if (filesToServe.isEmpty()) {
65+
return contextsToServe.getContextsToServe().stream()
66+
.filter(context -> context.getDatabasePath().isPresent())
67+
.filter(context -> {
68+
Path p = context.getDatabasePath().get();
69+
return (p.getFileName() + "-" + BackupFileUtil.getUniqueFilePrefix(p)).equals(id);
70+
})
71+
.findFirst()
72+
.orElseThrow(() -> new NotFoundException("No library with id " + id + " found"));
73+
}
74+
75+
Path library = getLibraryPath(id, filesToServe);
76+
try {
77+
return bibtexImporter.importDatabase(library).getDatabaseContext();
78+
} catch (IOException e) {
79+
LOGGER.warn("Could not find open library file {}", library, e);
80+
throw new InternalServerErrorException("Could not parse library", e);
81+
}
82+
}
83+
}

jabsrv/src/test/cayw.http

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,8 @@ GET http://localhost:23119/better-bibtex/cayw?librarypath=demo&format=biblatex&c
2020

2121
#### Serve a library specified by its path using the URL param
2222

23-
GET http://localhost:23119/better-bibtex/cayw?librarypath=C%3A%5CUsers%5CDEMO%5CDownloads%5CChocolate.bib
23+
GET http://localhost:23119/better-bibtex/cayw?librarypath=C%3A%5CUsers%5CDEMO%5CDownloads%5CChocolate.bib
24+
25+
#### Citation picker for Chocolate.bib in C:\git-repositories\JabRef\jablib\src\main\resources
26+
27+
GET http://localhost:23119/better-bibtex/cayw?libraryid=Chocolate.bib-6a732609&format=simple-json

0 commit comments

Comments
 (0)