Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to stream-based loading #11479

Merged
merged 16 commits into from
Jul 17, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.jabref.architecture;

/**
* Annotation to indicate that this logic class can use class.getResource().
* Mostly, because {@link java.nio.file.Path} is not used.
* See <a href="graal#7682">https://github.com/oracle/graal/issues/7682</a> for a longer discussion.
*/
public @interface AllowedToUseClassGetResource {
// The rationale
String value();
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* Annotation to indicate that this logic class can access swing
*/
public @interface AllowedToUseSwing {

// The rationale
String value();
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;

import org.jabref.architecture.AllowedToUseClassGetResource;
import org.jabref.logic.importer.FetcherException;

import com.airhacks.afterburner.views.ViewLoader;

@AllowedToUseClassGetResource("JavaFX internally handles the passed URLs properly.")
public class JournalInfoView extends VBox {
@FXML private Label title;
@FXML private Label categories;
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/jabref/gui/groups/GroupTreeView.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import javafx.scene.layout.StackPane;
import javafx.scene.text.Text;

import org.jabref.architecture.AllowedToUseClassGetResource;
import org.jabref.gui.DialogService;
import org.jabref.gui.DragAndDropDataFormats;
import org.jabref.gui.StateManager;
Expand Down Expand Up @@ -70,6 +71,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@AllowedToUseClassGetResource("JavaFX internally handles the passed URLs properly.")
public class GroupTreeView extends BorderPane {

private static final Logger LOGGER = LoggerFactory.getLogger(GroupTreeView.class);
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/org/jabref/gui/icon/IconTheme.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import javafx.scene.image.Image;
import javafx.scene.paint.Color;

import org.jabref.architecture.AllowedToUseClassGetResource;

import org.kordamp.ikonli.Ikon;
import org.kordamp.ikonli.IkonProvider;
import org.kordamp.ikonli.materialdesign2.MaterialDesignA;
Expand Down Expand Up @@ -50,6 +52,7 @@

import static java.util.EnumSet.allOf;

@AllowedToUseClassGetResource("JavaFX internally handles the passed URLs properly.")
public class IconTheme {

public static final Color DEFAULT_DISABLED_COLOR = Color.web("#c8c8c8");
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/org/jabref/gui/icon/JabRefIkonHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
import java.io.InputStream;
import java.net.URL;

import org.jabref.architecture.AllowedToUseClassGetResource;

import org.kordamp.ikonli.AbstractIkonHandler;
import org.kordamp.ikonli.Ikon;

@AllowedToUseClassGetResource("JavaFX internally handles the passed URLs properly.")
public class JabRefIkonHandler extends AbstractIkonHandler {

private static String FONT_RESOURCE = "/fonts/JabRefMaterialDesign.ttf";
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/jabref/gui/maintable/MainTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;

import org.jabref.architecture.AllowedToUseClassGetResource;
import org.jabref.gui.ClipBoardManager;
import org.jabref.gui.DialogService;
import org.jabref.gui.DragAndDropDataFormats;
Expand Down Expand Up @@ -60,6 +61,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@AllowedToUseClassGetResource("JavaFX internally handles the passed URLs properly.")
public class MainTable extends TableView<BibEntryTableViewModel> {

private static final Logger LOGGER = LoggerFactory.getLogger(MainTable.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import javafx.scene.layout.VBox;
import javafx.stage.Screen;

import org.jabref.architecture.AllowedToUseClassGetResource;
import org.jabref.gui.mergeentries.newmergedialog.fieldsmerger.FieldMergerFactory;
import org.jabref.gui.mergeentries.newmergedialog.toolbar.ThreeWayMergeToolbar;
import org.jabref.logic.l10n.Localization;
Expand All @@ -19,6 +20,7 @@
import org.jabref.model.entry.field.FieldProperty;
import org.jabref.preferences.PreferencesService;

@AllowedToUseClassGetResource("JavaFX internally handles the passed URLs properly.")
public class ThreeWayMergeView extends VBox {
public static final int GRID_COLUMN_MIN_WIDTH = 250;

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/jabref/gui/search/GlobalSearchBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;

import org.jabref.architecture.AllowedToUseClassGetResource;
import org.jabref.gui.ClipBoardManager;
import org.jabref.gui.DialogService;
import org.jabref.gui.LibraryTabContainer;
Expand Down Expand Up @@ -445,6 +446,7 @@ public void setSearchTerm(String searchTerm) {
UiTaskExecutor.runInJavaFXThread(() -> searchField.setText(searchTerm));
}

@AllowedToUseClassGetResource("JavaFX internally handles the passed URLs properly.")
private static class SearchPopupSkin<T> implements Skin<AutoCompletePopup<T>> {

private final AutoCompletePopup<T> control;
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/jabref/gui/search/SearchResultsTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;

import org.jabref.architecture.AllowedToUseClassGetResource;
import org.jabref.gui.DialogService;
import org.jabref.gui.StateManager;
import org.jabref.gui.maintable.BibEntryTableViewModel;
Expand All @@ -22,6 +23,7 @@
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.preferences.PreferencesService;

@AllowedToUseClassGetResource("JavaFX internally handles the passed URLs properly.")
public class SearchResultsTable extends TableView<BibEntryTableViewModel> {

public SearchResultsTable(SearchResultsTableDataModel model,
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/jabref/gui/theme/StyleSheet.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
import java.nio.file.Path;
import java.util.Optional;

import org.jabref.architecture.AllowedToUseClassGetResource;
import org.jabref.gui.JabRefGUI;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@AllowedToUseClassGetResource("JavaFX internally handles the passed URLs properly.")
abstract class StyleSheet {

static final String DATA_URL_PREFIX = "data:text/css;charset=utf-8;base64,";
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/gui/theme/StyleSheetFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public URL getSceneStylesheet() {
* This method allows callers to obtain the theme's additional stylesheet.
*
* @return the stylesheet location if there is an additional stylesheet present and available. The
* location will be a local URL. Typically it will be a {@code 'data:'} URL where the CSS is embedded. However for
* location will be a local URL. Typically, it will be a {@code 'data:'} URL where the CSS is embedded. However, for
* large themes it can be {@code 'file:'}.
*/
@Override
Expand Down
76 changes: 39 additions & 37 deletions src/main/java/org/jabref/logic/citationstyle/CitationStyle.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package org.jabref.logic.citationstyle;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
Expand All @@ -22,7 +22,6 @@

import org.jabref.logic.util.StandardFileType;

import de.undercouch.citeproc.helper.CSLUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.CharacterData;
Expand Down Expand Up @@ -57,31 +56,41 @@ private CitationStyle(final String filename, final String title, final String so
/**
* Creates an CitationStyle instance out of the style string
*/
private static Optional<CitationStyle> createCitationStyleFromSource(final String source, final String filename) {
if ((filename != null) && !filename.isEmpty() && (source != null) && !source.isEmpty()) {
try {
InputSource inputSource = new InputSource();
inputSource.setCharacterStream(new StringReader(stripInvalidProlog(source)));

Document doc = FACTORY.newDocumentBuilder().parse(inputSource);

// See CSL#canFormatBibliographies, checks if the tag exists
NodeList bibs = doc.getElementsByTagName("bibliography");
if (bibs.getLength() <= 0) {
LOGGER.debug("no bibliography element for file {} ", filename);
return Optional.empty();
}

NodeList nodes = doc.getElementsByTagName("info");
NodeList titleNode = ((Element) nodes.item(0)).getElementsByTagName("title");
String title = ((CharacterData) titleNode.item(0).getFirstChild()).getData();

return Optional.of(new CitationStyle(filename, title, source));
} catch (ParserConfigurationException | SAXException | IOException e) {
LOGGER.error("Error while parsing source", e);
private static Optional<CitationStyle> createCitationStyleFromSource(final InputStream source, final String filename) {
try {
// We need the content twice:
// First, for parsing it here for the name
// Second for the CSL library to parse it
String content = new String(source.readAllBytes());

Optional<String> title = getTitle(filename, content);
if (title.isEmpty()) {
return Optional.empty();
}

return Optional.of(new CitationStyle(filename, title.get(), content));
} catch (ParserConfigurationException | SAXException | IOException e) {
LOGGER.error("Error while parsing source", e);
return Optional.empty();
}
return Optional.empty();
}

private static Optional<String> getTitle(String filename, String content) throws SAXException, IOException, ParserConfigurationException {
// TODO: Switch to StAX parsing (to speed up - we need only the title)
InputSource inputSource = new InputSource(new StringReader(content));
Document doc = FACTORY.newDocumentBuilder().parse(inputSource);

// See CSL#canFormatBibliographies, checks if the tag exists
NodeList bibs = doc.getElementsByTagName("bibliography");
if (bibs.getLength() <= 0) {
LOGGER.debug("no bibliography element for file {} ", filename);
return Optional.empty();
}

NodeList nodes = doc.getElementsByTagName("info");
NodeList titleNode = ((Element) nodes.item(0)).getElementsByTagName("title");
String title = ((CharacterData) titleNode.item(0).getFirstChild()).getData();
return Optional.of(title);
}

private static String stripInvalidProlog(String source) {
Expand All @@ -102,18 +111,11 @@ public static Optional<CitationStyle> createCitationStyleFromFile(final String s
return Optional.empty();
}

try {
String text;
String internalFile = STYLES_ROOT + (styleFile.startsWith("/") ? "" : "/") + styleFile;
URL url = CitationStyle.class.getResource(internalFile);

if (url != null) {
text = CSLUtils.readURLToString(url, StandardCharsets.UTF_8.toString());
} else {
// if the url is null then the style is located outside the classpath
text = Files.readString(Path.of(styleFile));
}
return createCitationStyleFromSource(text, styleFile);
String internalFile = STYLES_ROOT + (styleFile.startsWith("/") ? "" : "/") + styleFile;
Path internalFilePath = Path.of(internalFile);
boolean isExternalFile = Files.exists(internalFilePath);
try (InputStream inputStream = isExternalFile ? Files.newInputStream(internalFilePath) : CitationStyle.class.getResourceAsStream(internalFile)) {
return createCitationStyleFromSource(inputStream, styleFile);
} catch (NoSuchFileException e) {
LOGGER.error("Could not find file: {}", styleFile, e);
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package org.jabref.logic.citationstyle;

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

import de.undercouch.citeproc.LocaleProvider;
import de.undercouch.citeproc.helper.CSLUtils;
import org.slf4j.Logger;

/**
* A {@link LocaleProvider} that loads locales from a directory in the current module.
Expand All @@ -16,20 +17,22 @@
*/
public class JabRefLocaleProvider implements LocaleProvider {

private static final Logger LOGGER = org.slf4j.LoggerFactory.getLogger(JabRefLocaleProvider.class);

private static final String LOCALES_ROOT = "/csl-locales";

private final Map<String, String> locales = new HashMap<>();

@Override
public String retrieveLocale(String lang) {
return locales.computeIfAbsent(lang, locale -> {
try {
URL url = getClass().getResource(LOCALES_ROOT + "/locales-" + locale + ".xml");
if (url == null) {
try (InputStream inputStream = getClass().getResourceAsStream(LOCALES_ROOT + "/locales-" + locale + ".xml")) {
if (inputStream == null) {
throw new IllegalArgumentException("Unable to load locale " + locale);
}
return CSLUtils.readURLToString(url, "UTF-8");
return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
} catch (IOException e) {
LOGGER.error("failed to read locale {}", locale, e);
throw new UncheckedIOException("failed to read locale " + locale, e);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
Expand Down Expand Up @@ -129,18 +128,8 @@ private static void addResourceFile(String name, String resource, ZipOutputStrea
}

private static void addFromResource(String resource, OutputStream out) {
URL url = OpenDocumentSpreadsheetCreator.class.getResource(resource);
try (InputStream in = url.openStream()) {
byte[] buffer = new byte[256];
synchronized (out) {
while (true) {
int bytesRead = in.read(buffer);
if (bytesRead == -1) {
break;
}
out.write(buffer, 0, bytesRead);
}
}
try (InputStream in = OpenDocumentSpreadsheetCreator.class.getResourceAsStream(resource)) {
in.transferTo(out);
} catch (IOException e) {
LOGGER.warn("Cannot get resource", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
Expand Down Expand Up @@ -111,18 +110,8 @@ private static void addResourceFile(String name, String resource, ZipOutputStrea
}

private static void addFromResource(String resource, OutputStream out) {
URL url = OpenOfficeDocumentCreator.class.getResource(resource);
try (InputStream in = url.openStream()) {
byte[] buffer = new byte[256];
synchronized (out) {
while (true) {
int bytesRead = in.read(buffer);
if (bytesRead == -1) {
break;
}
out.write(buffer, 0, bytesRead);
}
}
try (InputStream in = OpenOfficeDocumentCreator.class.getResourceAsStream(resource)) {
in.transferTo(out);
} catch (IOException e) {
LOGGER.warn("Cannot get resource", e);
}
Expand Down
Loading
Loading