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

Implement remote storage sync #642

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ gradlew text eol=lf

# .bib files have to be written using OS specific line endings to enable our tests working
*.bib text !eol
# Exception: The files used for the http server test - they should have linux line endings
src/test/resources/org/jabref/http/server/*.bib text eol=lf

# Citavi needs to be LF line ending
# This overwrites the setting of "*.bib"
Expand Down
28 changes: 28 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ dependencies {
implementation "org.tinylog:tinylog-api:2.6.1"
implementation "org.tinylog:slf4j-tinylog:2.6.1"
implementation "org.tinylog:tinylog-impl:2.6.1"
// route all requests to java.util.logging to SLF4J (which in turn routes to tinylog)
implementation 'org.slf4j:jul-to-slf4j:2.0.7'

implementation 'de.undercouch:citeproc-java:3.0.0-beta.2'

Expand All @@ -200,6 +202,26 @@ dependencies {

implementation group: 'net.harawata', name: 'appdirs', version: '1.2.1'

// JAX-RS implemented by Jersey
// API
implementation 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0'
// Implementation of the API
implementation 'org.glassfish.jersey.core:jersey-server:3.1.1'
// injection framework
implementation 'org.glassfish.jersey.inject:jersey-hk2:3.1.1'
implementation 'org.glassfish.hk2:hk2-api:2.6.1'
// testImplementation 'org.glassfish.hk2:hk2-testing:3.0.4'
// implementation 'org.glassfish.hk2:hk2-testing-jersey:3.0.4'
// testImplementation 'org.glassfish.hk2:hk2-junitrunner:3.0.4'
// HTTP server
// implementation 'org.glassfish.jersey.containers:jersey-container-netty-http:3.1.1'
implementation 'org.glassfish.jersey.containers:jersey-container-grizzly2-http:3.1.1'
testImplementation 'org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-grizzly2:3.1.1'
// OpenAPI generation
implementation 'io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.9'
// Allow objects "magically" to be mapped to JSON using GSON
// implementation 'org.glassfish.jersey.media:jersey-media-json-gson:3.1.1'

testImplementation 'io.github.classgraph:classgraph:4.8.157'
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
testImplementation 'org.junit.platform:junit-platform-launcher:1.9.2'
Expand Down Expand Up @@ -381,6 +403,12 @@ run {
'javafx.base/com.sun.javafx.event' : 'com.jfoenix'
]
}

if (project.hasProperty('application')){
if (application == 'httpserver'){
main = 'org.jabref.http.server.Server'
}
}
}

javadoc {
Expand Down
16 changes: 16 additions & 0 deletions docs/code-howtos/http-server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
parent: Code Howtos
---
# HTTP Server

## Get SSL Working

(Based on <https://stackoverflow.com/a/57511038/873282>)

Howto vor Windows - other operating systems work similar:

1. As admin `choco install mkcert`
2. As admin: `mkcert -install`
3. `cd %APPDATA%\..\local\org.jabref\jabref\ssl`
4. `mkcert -pkcs12 jabref.desktop jabref localhost 127.0.0.1 ::1`
5. Rename the file to `server.p12`
53 changes: 53 additions & 0 deletions docs/decisions/0027-http-return-bibtex-string.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
nav_order: 27
parent: Decision Records
---
<!-- we need to disable MD025, because we use the different heading "ADR Template" in the homepage (see above) than it is foreseen in the template -->
<!-- markdownlint-disable-next-line MD025 -->
# Return BibTeX string and CSL Item JSON in the API

## Context and Problem Statement

In the context of an http server, when a http client `GETs` a JSON data structure containing BibTeX data, which format should that have?

## Considered Options

* Offer both, BibTeX string and CSL JSON
* Return BibTeX as is as string
* Convert BibTeX to JSON

## Decision Outcome

Chosen option: "Offer both, BibTeX string and CSL JSON", because there are many browser libraries out there being able to parse BibTeX. Thus, we don't need to convert it.

## Pros and Cons of the Options

### Offer both, BibTeX string and CSL JSON

- Good, because this follows "Backend for Frontend"
- Good, because Word Addin works seamless with the data provided (and does not need another dependency)
- Good, because other clients can work with BibTeX data
- Bad, because two serializations have to be kept

### Return BibTeX as is as string

- Good, because we don't need to think about any conversion
- Bad, because it is unclear how to ship BibTeX data where the entry is dependent on
- Bad, because client needs add additional parsing logic

### Convert BibTeX to JSON

More thought has to be done when converting to JSON.
There seems to be a JSON format from [@citation-js/plugin-bibtex](https://www.npmjs.com/package/@citation-js/plugin-bibtex).
We could do an additional self-made JSON format, but this increases the number of available JSON serializations for BibTeX.

- Good, because it could flatten BibTeX data (example: `author = first # " and " # second`)
- Bad, because conversion is difficult in BibTeX special cases. For instance, if Strings are used (example: `author = first # " and " # second`) and one doesn't want to flatten ("normalize") this.

## More Information

Existing JavaScript BibTeX libraries:

* [bibtex-js](https://github.com/digitalheir/bibtex-js)
* [bibtexParseJS](https://github.com/ORCID/bibtexParseJs)
* [@citation-js/plugin-bibtex](https://www.npmjs.com/package/@citation-js/plugin-bibtex)
77 changes: 50 additions & 27 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
requires afterburner.fx;
requires com.jfoenix;
requires de.saxsys.mvvmfx;
requires reactfx;
requires de.saxsys.mvvmfx.validation;
requires org.fxmisc.flowless;

requires org.kordamp.ikonli.core;
requires org.kordamp.ikonli.javafx;
Expand All @@ -39,6 +42,7 @@

// Logging
requires org.slf4j;
requires jul.to.slf4j;
requires org.tinylog.api;
requires org.tinylog.api.slf4j;
requires org.tinylog.impl;
Expand All @@ -47,47 +51,64 @@
with org.jabref.gui.logging.GuiWriter,
org.jabref.gui.logging.ApplicationInsightsWriter;

// Preferences and XML
requires java.prefs;

// Annotations (@PostConstruct)
requires jakarta.annotation;
requires jakarta.inject;

// http server and client exchange
requires java.net.http;
requires jakarta.ws.rs;
requires grizzly.framework;

// OpenAPI generation
requires io.swagger.v3.core;
requires io.swagger.v3.oas.models;
requires io.swagger.v3.oas.integration;
requires io.swagger.v3.jaxrs2;

// data mapping
requires jakarta.xml.bind;
requires jdk.xml.dom;
requires com.google.gson;
requires com.fasterxml.jackson.databind;
requires com.fasterxml.jackson.dataformat.yaml;
requires com.fasterxml.jackson.datatype.jsr310;
// needs to be loaded here as it's otherwise not found at runtime
requires org.glassfish.jaxb.runtime;
requires jdk.xml.dom;

// Annotations (@PostConstruct)
requires jakarta.annotation;
// dependency injection using HK2
requires org.glassfish.hk2.api;

// Microsoft application insights
requires applicationinsights.core;
requires applicationinsights.logging.log4j2;

// Libre Office
requires org.libreoffice.uno;

// Other modules
requires com.google.common;
requires jakarta.inject;
requires reactfx;
requires commons.cli;
requires com.github.tomtung.latex2unicode;
requires fastparse;
requires jbibtex;
requires citeproc.java;
requires de.saxsys.mvvmfx.validation;
requires com.google.gson;
// http clients
requires unirest.java;
requires org.apache.httpcomponents.httpclient;
requires org.jsoup;
requires org.apache.commons.csv;
requires io.github.javadiffutils;
requires java.string.similarity;

// SQL databases
requires ojdbc10;
requires org.postgresql.jdbc;
requires org.mariadb.jdbc;
uses org.mariadb.jdbc.credential.CredentialPlugin;

// Apache Commons and other (similar) helper libraries
requires commons.cli;
requires org.apache.commons.csv;
requires org.apache.commons.lang3;
requires org.antlr.antlr4.runtime;
requires org.fxmisc.flowless;
requires com.google.common;
requires io.github.javadiffutils;
requires java.string.similarity;

requires com.github.tomtung.latex2unicode;
requires fastparse;

requires jbibtex;
requires citeproc.java;

requires pdfbox;
requires xmpbox;
Expand All @@ -96,7 +117,6 @@
requires flexmark;
requires flexmark.util.ast;
requires flexmark.util.data;
requires com.h2database.mvstore;

// fulltext search
requires org.apache.lucene.core;
Expand All @@ -108,14 +128,17 @@
requires org.apache.lucene.analysis.common;
requires org.apache.lucene.highlighter;

requires com.fasterxml.jackson.databind;
requires com.fasterxml.jackson.dataformat.yaml;
requires com.fasterxml.jackson.datatype.jsr310;
requires net.harawata.appdirs;
requires com.sun.jna;
requires com.sun.jna.platform;

requires org.eclipse.jgit;
uses org.eclipse.jgit.transport.SshSessionFactory;
uses org.eclipse.jgit.lib.GpgSigner;

// other libraries
requires com.h2database.mvstore;
requires org.antlr.antlr4.runtime;
requires org.libreoffice.uno;

}
21 changes: 14 additions & 7 deletions src/main/java/org/jabref/cli/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.apache.commons.cli.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.tinylog.configuration.Configuration;

/**
Expand All @@ -46,6 +47,7 @@ public class Launcher {
private static String[] ARGUMENTS;

public static void main(String[] args) {
routeLoggingToSlf4J();
ARGUMENTS = args;
addLogToDisk();
try {
Expand Down Expand Up @@ -84,6 +86,11 @@ public static void main(String[] args) {
}
}

private static void routeLoggingToSlf4J() {
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
}

/**
* This needs to be called as early as possible. After the first log write, it
* is not possible to alter
Expand All @@ -92,10 +99,10 @@ public static void main(String[] args) {
private static void addLogToDisk() {
Path directory = Path.of(AppDirsFactory.getInstance()
.getUserDataDir(
OS.APP_DIR_APP_NAME,
"logs",
OS.APP_DIR_APP_AUTHOR))
.resolve(new BuildInfo().version.toString());
OS.APP_DIR_APP_NAME,
"logs",
OS.APP_DIR_APP_AUTHOR))
.resolve(new BuildInfo().version.toString());
try {
Files.createDirectories(directory);
} catch (IOException e) {
Expand Down Expand Up @@ -183,9 +190,9 @@ private static void clearOldSearchIndices() {
&& !path.equals(currentIndexPath)) {
LOGGER.info("Deleting out-of-date fulltext search index at {}.", path);
Files.walk(path)
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
}
}
} catch (IOException e) {
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/org/jabref/http/MediaType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.jabref.http;

public class MediaType {
public static final String BIBTEX = "application/x-bibtex";
public static final String JSON_CSL_ITEM = "application/x-bibtex-library-csl+json";
}
53 changes: 53 additions & 0 deletions src/main/java/org/jabref/http/client/SyncClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.jabref.http.client;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;

import org.jabref.model.database.BibDatabaseContext;
import org.jabref.http.dto.BibEntryDTO;

Choose a reason for hiding this comment

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

🚫 [reviewdog] <com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck> reported by reviewdog 🐶
Wrong order for 'org.jabref.http.dto.BibEntryDTO' import.


public class SyncClient {

private final BibDatabaseContext bibDatabaseContext;
private Long lastSynchronizedGlobalRevision = -1L;

private HttpClient httpClient = HttpClient.newHttpClient();

/**
* Initializes a client for the given context
*/
public SyncClient(BibDatabaseContext bibDatabaseContext) throws IllegalArgumentException {
if (bibDatabaseContext.getDatabasePath().isEmpty()) {
throw new IllegalArgumentException("Unsaved libraries not yet supported.");
}
this.bibDatabaseContext = bibDatabaseContext;
}

/**
* Client needs to store the state of Id and entry locally to be able to handle external changes.
* This is done using the "dirty" flag.
*/
private void synchronizeWithLocalView() {
}

public List<BibEntryDTO> getChanges() throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://localhost:8080/updates?lastUpdate=0"))
.GET()
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
return null;
}

/**
* Synchronizes the given library with the server.
* <p>
* Pre-condition: Connection with server works
*/
public void synchronize(BibDatabaseContext bibDatabaseContext) {
}
}
Loading