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

Add oaDOI fulltext fetcher #3581

Merged
merged 2 commits into from
Jan 2, 2018
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ We refer to [GitHub issues](https://github.com/JabRef/jabref/issues) by using `#
## [Unreleased]

### Changed
- 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.

### Fixed

Expand Down
24 changes: 2 additions & 22 deletions src/main/java/org/jabref/logic/importer/FulltextFetchers.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,6 @@
import java.util.List;
import java.util.Optional;

import org.jabref.logic.importer.fetcher.ACS;
import org.jabref.logic.importer.fetcher.ArXiv;
import org.jabref.logic.importer.fetcher.DoiResolution;
import org.jabref.logic.importer.fetcher.GoogleScholar;
import org.jabref.logic.importer.fetcher.IEEE;
import org.jabref.logic.importer.fetcher.ScienceDirect;
import org.jabref.logic.importer.fetcher.SpringerLink;
import org.jabref.logic.net.URLDownload;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.FieldName;
Expand All @@ -30,26 +23,13 @@ public class FulltextFetchers {
private final List<FulltextFetcher> finders = new ArrayList<>();

public FulltextFetchers(ImportFormatPreferences importFormatPreferences) {
// Ordering is important, authorities first!
// Publisher
finders.add(new DoiResolution());
finders.add(new ScienceDirect());
finders.add(new SpringerLink());
finders.add(new ACS());
finders.add(new ArXiv(importFormatPreferences));
finders.add(new IEEE());
// Meta search
finders.add(new GoogleScholar(importFormatPreferences));
this(WebFetchers.getFullTextFetchers(importFormatPreferences));
}

public FulltextFetchers(List<FulltextFetcher> fetcher) {
FulltextFetchers(List<FulltextFetcher> fetcher) {
finders.addAll(fetcher);
}

public List<FulltextFetcher> getFetchers() {
return finders;
}

public Optional<URL> findFullTextPDF(BibEntry entry) {
// for accuracy, fetch DOI first but do not modify entry
BibEntry clonedEntry = (BibEntry) entry.clone();
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/org/jabref/logic/importer/WebFetchers.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@
import java.util.List;
import java.util.Optional;

import org.jabref.logic.importer.fetcher.ACS;
import org.jabref.logic.importer.fetcher.ArXiv;
import org.jabref.logic.importer.fetcher.AstrophysicsDataSystem;
import org.jabref.logic.importer.fetcher.CrossRef;
import org.jabref.logic.importer.fetcher.DBLPFetcher;
import org.jabref.logic.importer.fetcher.DiVA;
import org.jabref.logic.importer.fetcher.DoiFetcher;
import org.jabref.logic.importer.fetcher.DoiResolution;
import org.jabref.logic.importer.fetcher.GoogleScholar;
import org.jabref.logic.importer.fetcher.GvkFetcher;
import org.jabref.logic.importer.fetcher.IEEE;
import org.jabref.logic.importer.fetcher.IacrEprintFetcher;
import org.jabref.logic.importer.fetcher.IsbnFetcher;
import org.jabref.logic.importer.fetcher.LibraryOfCongress;
import org.jabref.logic.importer.fetcher.MathSciNet;
import org.jabref.logic.importer.fetcher.MedlineFetcher;
import org.jabref.logic.importer.fetcher.OpenAccessDoi;
import org.jabref.logic.importer.fetcher.ScienceDirect;
import org.jabref.logic.importer.fetcher.SpringerLink;
import org.jabref.logic.importer.fetcher.TitleFetcher;
import org.jabref.logic.importer.fetcher.zbMATH;
import org.jabref.model.entry.FieldName;
Expand Down Expand Up @@ -113,4 +119,22 @@ public static List<IdFetcher> getIdFetchers(ImportFormatPreferences importFormat
list.sort(Comparator.comparing(WebFetcher::getName));
return list;
}

public static List<FulltextFetcher> getFullTextFetchers(ImportFormatPreferences importFormatPreferences) {
List<FulltextFetcher> fetchers = new ArrayList<>();

// Ordering is important, authorities first!
// Publisher
fetchers.add(new DoiResolution());
fetchers.add(new ScienceDirect());
fetchers.add(new SpringerLink());
fetchers.add(new ACS());
fetchers.add(new ArXiv(importFormatPreferences));
fetchers.add(new IEEE());
// Meta search
fetchers.add(new GoogleScholar(importFormatPreferences));
fetchers.add(new OpenAccessDoi());

return fetchers;
}
}
58 changes: 58 additions & 0 deletions src/main/java/org/jabref/logic/importer/fetcher/OpenAccessDoi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.jabref.logic.importer.fetcher;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Objects;
import java.util.Optional;

import org.jabref.logic.importer.FulltextFetcher;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.FieldName;
import org.jabref.model.entry.identifier.DOI;

import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import org.json.JSONObject;

/**
* A fulltext fetcher that uses <a href="https://oadoi.org/">oaDOI</a>.
*
* @implSpec API is documented at https://oadoi.org/api/v2
*/
public class OpenAccessDoi implements FulltextFetcher {
private static String API_URL = "https://api.oadoi.org/v2/";

@Override
public Optional<URL> findFullText(BibEntry entry) throws IOException {
Objects.requireNonNull(entry);

Optional<DOI> doi = entry.getField(FieldName.DOI)
.flatMap(DOI::parse);
if (doi.isPresent()) {
try {
return findFullText(doi.get());
} catch (UnirestException e) {
throw new IOException(e);
}
} else {
return Optional.empty();
}
}

public Optional<URL> findFullText(DOI doi) throws UnirestException, MalformedURLException {
HttpResponse<JsonNode> jsonResponse = Unirest.get(API_URL + doi.getDOI() + "?email=developers@jabref.org")
.header("accept", "application/json")
.asJson();
JSONObject root = jsonResponse.getBody().getObject();
Optional<String> url = Optional.ofNullable(root.optJSONObject("best_oa_location"))
.map(location -> location.optString("url"));
if (url.isPresent()) {
return Optional.of(new URL(url.get()));
} else {
return Optional.empty();
}
}
}
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/model/entry/identifier/DOI.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public DOI(String doi) {
*/
public static Optional<DOI> parse(String doi) {
try {
return Optional.ofNullable(new DOI(doi));
return Optional.of(new DOI(doi));
} catch (IllegalArgumentException | NullPointerException e) {
return Optional.empty();
}
Expand Down
12 changes: 10 additions & 2 deletions src/test/java/org/jabref/logic/importer/WebFetchersTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,19 @@ public void getEntryBasedFetchersReturnsAllFetcherDerivingFromEntryBasedFetcher(

@Test
public void getSearchBasedFetchersReturnsAllFetcherDerivingFromSearchBasedFetcher() throws Exception {
List<SearchBasedFetcher> idFetchers = WebFetchers.getSearchBasedFetchers(importFormatPreferences);
List<SearchBasedFetcher> searchBasedFetchers = WebFetchers.getSearchBasedFetchers(importFormatPreferences);

Set<Class<? extends SearchBasedFetcher>> expected = reflections.getSubTypesOf(SearchBasedFetcher.class);
expected.remove(SearchBasedParserFetcher.class);
assertEquals(expected, getClasses(idFetchers));
assertEquals(expected, getClasses(searchBasedFetchers));
}

@Test
public void getFullTextFetchersReturnsAllFetcherDerivingFromFullTextFetcher() throws Exception {
List<FulltextFetcher> fullTextFetchers = WebFetchers.getFullTextFetchers(importFormatPreferences);

Set<Class<? extends FulltextFetcher>> expected = reflections.getSubTypesOf(FulltextFetcher.class);
assertEquals(expected, getClasses(fullTextFetchers));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import java.util.Optional;

import org.jabref.logic.importer.FulltextFetcher;
import org.jabref.logic.importer.FulltextFetchers;
import org.jabref.logic.importer.ImportFormatPreferences;
import org.jabref.logic.importer.WebFetchers;
import org.jabref.model.entry.BibEntry;

import org.junit.jupiter.params.ParameterizedTest;
Expand All @@ -18,7 +18,7 @@
class FulltextFetcherTest {

private static List<FulltextFetcher> fetcherProvider() {
return new FulltextFetchers(mock(ImportFormatPreferences.class)).getFetchers();
return WebFetchers.getFullTextFetchers(mock(ImportFormatPreferences.class));
}

@ParameterizedTest
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package org.jabref.logic.importer.fetcher;

import java.io.IOException;
import java.net.URL;
import java.util.Optional;

import org.jabref.model.entry.BibEntry;
import org.jabref.testutils.category.FetcherTest;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

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

@FetcherTest
class OpenAccessDoiTest {

private OpenAccessDoi finder;
private BibEntry entry;

@BeforeEach
void setUp() {
finder = new OpenAccessDoi();
entry = new BibEntry();
}

@Test
void findByDOI() throws IOException {
entry.setField("doi", "10.1038/nature12373");

assertEquals(
Optional.of(new URL("https://dash.harvard.edu/bitstream/handle/1/12285462/Nanometer-Scale%20Thermometry.pdf?sequence=1")),
finder.findFullText(entry)
);
}

@Test
void notFoundByDOI() throws IOException {
entry.setField("doi", "10.1186/unknown-doi");

assertEquals(Optional.empty(), finder.findFullText(entry));
}
}