Skip to content

Commit b246b9c

Browse files
authored
Add oaDOI fulltext fetcher (#3581)
* Add oaDOI fulltext fetcher * Rename to OpenAccessDoi
1 parent d381839 commit b246b9c

File tree

8 files changed

+141
-27
lines changed

8 files changed

+141
-27
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `#
1212
## [Unreleased]
1313

1414
### Changed
15+
- We added [oaDOI](https://oadoi.org/) as a fulltext provider, so that JabRef is now able to provide fulltexts for more than 90 million open-access articles.
1516

1617

1718
### Fixed

src/main/java/org/jabref/logic/importer/FulltextFetchers.java

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,6 @@
66
import java.util.List;
77
import java.util.Optional;
88

9-
import org.jabref.logic.importer.fetcher.ACS;
10-
import org.jabref.logic.importer.fetcher.ArXiv;
11-
import org.jabref.logic.importer.fetcher.DoiResolution;
12-
import org.jabref.logic.importer.fetcher.GoogleScholar;
13-
import org.jabref.logic.importer.fetcher.IEEE;
14-
import org.jabref.logic.importer.fetcher.ScienceDirect;
15-
import org.jabref.logic.importer.fetcher.SpringerLink;
169
import org.jabref.logic.net.URLDownload;
1710
import org.jabref.model.entry.BibEntry;
1811
import org.jabref.model.entry.FieldName;
@@ -30,26 +23,13 @@ public class FulltextFetchers {
3023
private final List<FulltextFetcher> finders = new ArrayList<>();
3124

3225
public FulltextFetchers(ImportFormatPreferences importFormatPreferences) {
33-
// Ordering is important, authorities first!
34-
// Publisher
35-
finders.add(new DoiResolution());
36-
finders.add(new ScienceDirect());
37-
finders.add(new SpringerLink());
38-
finders.add(new ACS());
39-
finders.add(new ArXiv(importFormatPreferences));
40-
finders.add(new IEEE());
41-
// Meta search
42-
finders.add(new GoogleScholar(importFormatPreferences));
26+
this(WebFetchers.getFullTextFetchers(importFormatPreferences));
4327
}
4428

45-
public FulltextFetchers(List<FulltextFetcher> fetcher) {
29+
FulltextFetchers(List<FulltextFetcher> fetcher) {
4630
finders.addAll(fetcher);
4731
}
4832

49-
public List<FulltextFetcher> getFetchers() {
50-
return finders;
51-
}
52-
5333
public Optional<URL> findFullTextPDF(BibEntry entry) {
5434
// for accuracy, fetch DOI first but do not modify entry
5535
BibEntry clonedEntry = (BibEntry) entry.clone();

src/main/java/org/jabref/logic/importer/WebFetchers.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,25 @@
55
import java.util.List;
66
import java.util.Optional;
77

8+
import org.jabref.logic.importer.fetcher.ACS;
89
import org.jabref.logic.importer.fetcher.ArXiv;
910
import org.jabref.logic.importer.fetcher.AstrophysicsDataSystem;
1011
import org.jabref.logic.importer.fetcher.CrossRef;
1112
import org.jabref.logic.importer.fetcher.DBLPFetcher;
1213
import org.jabref.logic.importer.fetcher.DiVA;
1314
import org.jabref.logic.importer.fetcher.DoiFetcher;
15+
import org.jabref.logic.importer.fetcher.DoiResolution;
1416
import org.jabref.logic.importer.fetcher.GoogleScholar;
1517
import org.jabref.logic.importer.fetcher.GvkFetcher;
18+
import org.jabref.logic.importer.fetcher.IEEE;
1619
import org.jabref.logic.importer.fetcher.IacrEprintFetcher;
1720
import org.jabref.logic.importer.fetcher.IsbnFetcher;
1821
import org.jabref.logic.importer.fetcher.LibraryOfCongress;
1922
import org.jabref.logic.importer.fetcher.MathSciNet;
2023
import org.jabref.logic.importer.fetcher.MedlineFetcher;
24+
import org.jabref.logic.importer.fetcher.OpenAccessDoi;
25+
import org.jabref.logic.importer.fetcher.ScienceDirect;
26+
import org.jabref.logic.importer.fetcher.SpringerLink;
2127
import org.jabref.logic.importer.fetcher.TitleFetcher;
2228
import org.jabref.logic.importer.fetcher.zbMATH;
2329
import org.jabref.model.entry.FieldName;
@@ -113,4 +119,22 @@ public static List<IdFetcher> getIdFetchers(ImportFormatPreferences importFormat
113119
list.sort(Comparator.comparing(WebFetcher::getName));
114120
return list;
115121
}
122+
123+
public static List<FulltextFetcher> getFullTextFetchers(ImportFormatPreferences importFormatPreferences) {
124+
List<FulltextFetcher> fetchers = new ArrayList<>();
125+
126+
// Ordering is important, authorities first!
127+
// Publisher
128+
fetchers.add(new DoiResolution());
129+
fetchers.add(new ScienceDirect());
130+
fetchers.add(new SpringerLink());
131+
fetchers.add(new ACS());
132+
fetchers.add(new ArXiv(importFormatPreferences));
133+
fetchers.add(new IEEE());
134+
// Meta search
135+
fetchers.add(new GoogleScholar(importFormatPreferences));
136+
fetchers.add(new OpenAccessDoi());
137+
138+
return fetchers;
139+
}
116140
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package org.jabref.logic.importer.fetcher;
2+
3+
import java.io.IOException;
4+
import java.net.MalformedURLException;
5+
import java.net.URL;
6+
import java.util.Objects;
7+
import java.util.Optional;
8+
9+
import org.jabref.logic.importer.FulltextFetcher;
10+
import org.jabref.model.entry.BibEntry;
11+
import org.jabref.model.entry.FieldName;
12+
import org.jabref.model.entry.identifier.DOI;
13+
14+
import com.mashape.unirest.http.HttpResponse;
15+
import com.mashape.unirest.http.JsonNode;
16+
import com.mashape.unirest.http.Unirest;
17+
import com.mashape.unirest.http.exceptions.UnirestException;
18+
import org.json.JSONObject;
19+
20+
/**
21+
* A fulltext fetcher that uses <a href="https://oadoi.org/">oaDOI</a>.
22+
*
23+
* @implSpec API is documented at https://oadoi.org/api/v2
24+
*/
25+
public class OpenAccessDoi implements FulltextFetcher {
26+
private static String API_URL = "https://api.oadoi.org/v2/";
27+
28+
@Override
29+
public Optional<URL> findFullText(BibEntry entry) throws IOException {
30+
Objects.requireNonNull(entry);
31+
32+
Optional<DOI> doi = entry.getField(FieldName.DOI)
33+
.flatMap(DOI::parse);
34+
if (doi.isPresent()) {
35+
try {
36+
return findFullText(doi.get());
37+
} catch (UnirestException e) {
38+
throw new IOException(e);
39+
}
40+
} else {
41+
return Optional.empty();
42+
}
43+
}
44+
45+
public Optional<URL> findFullText(DOI doi) throws UnirestException, MalformedURLException {
46+
HttpResponse<JsonNode> jsonResponse = Unirest.get(API_URL + doi.getDOI() + "[email protected]")
47+
.header("accept", "application/json")
48+
.asJson();
49+
JSONObject root = jsonResponse.getBody().getObject();
50+
Optional<String> url = Optional.ofNullable(root.optJSONObject("best_oa_location"))
51+
.map(location -> location.optString("url"));
52+
if (url.isPresent()) {
53+
return Optional.of(new URL(url.get()));
54+
} else {
55+
return Optional.empty();
56+
}
57+
}
58+
}

src/main/java/org/jabref/model/entry/identifier/DOI.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ public DOI(String doi) {
9595
*/
9696
public static Optional<DOI> parse(String doi) {
9797
try {
98-
return Optional.ofNullable(new DOI(doi));
98+
return Optional.of(new DOI(doi));
9999
} catch (IllegalArgumentException | NullPointerException e) {
100100
return Optional.empty();
101101
}

src/test/java/org/jabref/logic/importer/WebFetchersTest.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,19 @@ public void getEntryBasedFetchersReturnsAllFetcherDerivingFromEntryBasedFetcher(
5151

5252
@Test
5353
public void getSearchBasedFetchersReturnsAllFetcherDerivingFromSearchBasedFetcher() throws Exception {
54-
List<SearchBasedFetcher> idFetchers = WebFetchers.getSearchBasedFetchers(importFormatPreferences);
54+
List<SearchBasedFetcher> searchBasedFetchers = WebFetchers.getSearchBasedFetchers(importFormatPreferences);
5555

5656
Set<Class<? extends SearchBasedFetcher>> expected = reflections.getSubTypesOf(SearchBasedFetcher.class);
5757
expected.remove(SearchBasedParserFetcher.class);
58-
assertEquals(expected, getClasses(idFetchers));
58+
assertEquals(expected, getClasses(searchBasedFetchers));
59+
}
60+
61+
@Test
62+
public void getFullTextFetchersReturnsAllFetcherDerivingFromFullTextFetcher() throws Exception {
63+
List<FulltextFetcher> fullTextFetchers = WebFetchers.getFullTextFetchers(importFormatPreferences);
64+
65+
Set<Class<? extends FulltextFetcher>> expected = reflections.getSubTypesOf(FulltextFetcher.class);
66+
assertEquals(expected, getClasses(fullTextFetchers));
5967
}
6068

6169
@Test

src/test/java/org/jabref/logic/importer/fetcher/FulltextFetcherTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
import java.util.Optional;
55

66
import org.jabref.logic.importer.FulltextFetcher;
7-
import org.jabref.logic.importer.FulltextFetchers;
87
import org.jabref.logic.importer.ImportFormatPreferences;
8+
import org.jabref.logic.importer.WebFetchers;
99
import org.jabref.model.entry.BibEntry;
1010

1111
import org.junit.jupiter.params.ParameterizedTest;
@@ -18,7 +18,7 @@
1818
class FulltextFetcherTest {
1919

2020
private static List<FulltextFetcher> fetcherProvider() {
21-
return new FulltextFetchers(mock(ImportFormatPreferences.class)).getFetchers();
21+
return WebFetchers.getFullTextFetchers(mock(ImportFormatPreferences.class));
2222
}
2323

2424
@ParameterizedTest
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.jabref.logic.importer.fetcher;
2+
3+
import java.io.IOException;
4+
import java.net.URL;
5+
import java.util.Optional;
6+
7+
import org.jabref.model.entry.BibEntry;
8+
import org.jabref.testutils.category.FetcherTest;
9+
10+
import org.junit.jupiter.api.BeforeEach;
11+
import org.junit.jupiter.api.Test;
12+
13+
import static org.junit.jupiter.api.Assertions.assertEquals;
14+
15+
@FetcherTest
16+
class OpenAccessDoiTest {
17+
18+
private OpenAccessDoi finder;
19+
private BibEntry entry;
20+
21+
@BeforeEach
22+
void setUp() {
23+
finder = new OpenAccessDoi();
24+
entry = new BibEntry();
25+
}
26+
27+
@Test
28+
void findByDOI() throws IOException {
29+
entry.setField("doi", "10.1038/nature12373");
30+
31+
assertEquals(
32+
Optional.of(new URL("https://dash.harvard.edu/bitstream/handle/1/12285462/Nanometer-Scale%20Thermometry.pdf?sequence=1")),
33+
finder.findFullText(entry)
34+
);
35+
}
36+
37+
@Test
38+
void notFoundByDOI() throws IOException {
39+
entry.setField("doi", "10.1186/unknown-doi");
40+
41+
assertEquals(Optional.empty(), finder.findFullText(entry));
42+
}
43+
}

0 commit comments

Comments
 (0)