diff --git a/CHANGELOG b/CHANGELOG index 7f78e8e2693..05dca449681 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,5 @@ [master] + - Feature: Search DOAJ, Directory of Open Access Journals - Removes options to set PDF and PS directories per .bib database as the general options have also been deleted. - Removes option to hide the BibTeX Code tab in the entry editor. - Changes the old integrity check by improving the code base (+tests) and converting it to a simple issues table diff --git a/src/main/java/net/sf/jabref/importer/fetcher/DOAJFetcher.java b/src/main/java/net/sf/jabref/importer/fetcher/DOAJFetcher.java new file mode 100644 index 00000000000..d7245673693 --- /dev/null +++ b/src/main/java/net/sf/jabref/importer/fetcher/DOAJFetcher.java @@ -0,0 +1,146 @@ +/* Copyright (C) 2015 Oscar Gustafsson. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +package net.sf.jabref.importer.fetcher; + +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONArray; +import org.json.JSONObject; + +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 net.sf.jabref.importer.ImportInspector; +import net.sf.jabref.importer.OutputPrinter; +import net.sf.jabref.importer.fileformat.JSONEntryParser; +import net.sf.jabref.logic.l10n.Localization; +import net.sf.jabref.model.entry.BibtexEntry; + +public class DOAJFetcher implements EntryFetcher { + + private final String searchURL = "https://doaj.org/api/v1/search/articles/"; + private static final Log LOGGER = LogFactory.getLog(DOAJFetcher.class); + private final int maxPerPage = 100; + private boolean shouldContinue; + + + private final JSONEntryParser jsonConverter = new JSONEntryParser(); + + public DOAJFetcher() { + super(); + } + + @Override + public void stopFetching() { + shouldContinue = false; + } + + @Override + public boolean processQuery(String query, ImportInspector inspector, OutputPrinter status) { + shouldContinue = true; + try { + status.setStatus(Localization.lang("Searching DOAJ...")); + HttpResponse jsonResponse; + jsonResponse = Unirest.get(searchURL + query + "?pageSize=1").header("accept", "application/json").asJson(); + JSONObject jo = jsonResponse.getBody().getObject(); + int hits = jo.getInt("total"); + int numberToFetch = 0; + if (hits > 0) { + if (hits > maxPerPage) { + while (true) { + String strCount = JOptionPane + .showInputDialog( + Localization.lang("References found") + ": " + hits + " " + + Localization.lang("Number of references to fetch?"), + Integer.toString(hits)); + + if (strCount == null) { + status.setStatus(Localization.lang("DOAJ search canceled")); + return false; + } + + try { + numberToFetch = Integer.parseInt(strCount.trim()); + break; + } catch (RuntimeException ex) { + status.showMessage(Localization.lang("Please enter a valid number")); + } + } + } else { + numberToFetch = hits; + } + + int fetched = 0; // Keep track of number of items fetched for the progress bar + for (int page = 1; ((page - 1) * maxPerPage) <= numberToFetch; page++) { + if (!shouldContinue) { + break; + } + + int noToFetch = Math.min(maxPerPage, numberToFetch - ((page - 1) * maxPerPage)); + jsonResponse = Unirest.get(searchURL + query + "?page=" + page + "&pageSize=" + noToFetch) + .header("accept", "application/json").asJson(); + jo = jsonResponse.getBody().getObject(); + if (jo.has("results")) { + JSONArray results = jo.getJSONArray("results"); + for (int i = 0; i < results.length(); i++) { + JSONObject bibJsonEntry = results.getJSONObject(i).getJSONObject("bibjson"); + BibtexEntry entry = jsonConverter.BibJSONtoBibtex(bibJsonEntry); + inspector.addEntry(entry); + fetched++; + inspector.setProgress(fetched, numberToFetch); + } + } + } + return true; + } else { + status.showMessage(Localization.lang("No entries found for the search string '%0'", query), + Localization.lang("Search DOAJ"), JOptionPane.INFORMATION_MESSAGE); + return false; + } + } catch (UnirestException e) { + LOGGER.warn("Problem searching DOAJ", e); + return false; + } + + } + + @Override + public String getTitle() { + return "DOAJ"; + } + + @Override + public String getKeyName() { + return "DOAJ"; + } + + @Override + public String getHelpPage() { + return "DOAJHelp.html"; + } + + @Override + public JPanel getOptionsPanel() { + // No additional options available + return null; + } + +} diff --git a/src/main/java/net/sf/jabref/importer/fetcher/EntryFetchers.java b/src/main/java/net/sf/jabref/importer/fetcher/EntryFetchers.java index d2b0c58889a..1b5d2410294 100644 --- a/src/main/java/net/sf/jabref/importer/fetcher/EntryFetchers.java +++ b/src/main/java/net/sf/jabref/importer/fetcher/EntryFetchers.java @@ -42,6 +42,7 @@ public EntryFetchers() { entryFetchers.add(new SPIRESFetcher()); entryFetchers.add(new ACMPortalFetcher()); entryFetchers.add(new GoogleScholarFetcher()); + entryFetchers.add(new DOAJFetcher()); } public List getEntryFetchers() { diff --git a/src/main/java/net/sf/jabref/importer/fileformat/JSONEntryParser.java b/src/main/java/net/sf/jabref/importer/fileformat/JSONEntryParser.java new file mode 100644 index 00000000000..b6a4204bdc5 --- /dev/null +++ b/src/main/java/net/sf/jabref/importer/fileformat/JSONEntryParser.java @@ -0,0 +1,150 @@ +/* Copyright (C) 2015 Oscar Gustafsson. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +package net.sf.jabref.importer.fileformat; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONArray; +import org.json.JSONObject; + +import net.sf.jabref.model.entry.BibtexEntry; +import net.sf.jabref.model.entry.BibtexEntryTypes; + +public class JSONEntryParser { + + private static final Log LOGGER = LogFactory.getLog(JSONEntryParser.class); + + + public JSONEntryParser() { + + } + + public BibtexEntry BibJSONtoBibtex(JSONObject bibJsonEntry) { + // Fields that are directly accessible at the top level BibJson object + String[] singleFieldStrings = {"year", "title", "abstract", "month"}; + + // Fields that are accessible in the journal part of the BibJson object + String[] journalSingleFieldStrings = {"publisher", "number", "volume"}; + + + + BibtexEntry entry = new BibtexEntry(); + entry.setType(BibtexEntryTypes.ARTICLE); + + // Authors + if (bibJsonEntry.has("author")) { + JSONArray authors = bibJsonEntry.getJSONArray("author"); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < authors.length(); i++) { + if (authors.getJSONObject(i).has("name")) { + sb.append(authors.getJSONObject(i).getString("name")); + if (i < (authors.length() - 1)) { + sb.append(" and "); + } + } else { + LOGGER.info("Empty author name."); + } + } + entry.setField("author", sb.toString()); + } else { + LOGGER.info("No author found."); + } + + // Direct accessible fields + for (String field : singleFieldStrings) { + if (bibJsonEntry.has(field)) { + entry.setField(field, bibJsonEntry.getString(field)); + } + } + + // Page numbers + if (bibJsonEntry.has("start_page")) { + if (bibJsonEntry.has("end_page")) { + entry.setField("pages", + bibJsonEntry.getString("start_page") + "--" + bibJsonEntry.getString("end_page")); + } else { + entry.setField("pages", bibJsonEntry.getString("start_page")); + } + } + + // Journal + if (bibJsonEntry.has("journal")) { + JSONObject journal = bibJsonEntry.getJSONObject("journal"); + // Journal title + if (journal.has("title")) { + entry.setField("journal", journal.getString("title")); + } else { + LOGGER.info("No journal title found."); + } + // Other journal related fields + for (String field : journalSingleFieldStrings) { + if (journal.has(field)) { + entry.setField(field, journal.getString(field)); + } + } + } else { + LOGGER.info("No journal information found."); + } + + // Keywords + if (bibJsonEntry.has("keywords")) { + JSONArray keywords = bibJsonEntry.getJSONArray("keywords"); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < keywords.length(); i++) { + if (!keywords.isNull(i)) { + sb.append(keywords.getString(i)); + if (i < (keywords.length() - 1)) { + sb.append(", "); + } + } + } + entry.setField("keywords", sb.toString()); + } + + // Identifiers + if (bibJsonEntry.has("identifier")) { + JSONArray identifiers = bibJsonEntry.getJSONArray("identifier"); + for (int i = 0; i < identifiers.length(); i++) { + String type = identifiers.getJSONObject(i).getString("type"); + if (type.equals("doi")) { + entry.setField("doi", identifiers.getJSONObject(i).getString("id")); + } else if (type.equals("pissn")) { + entry.setField("issn", identifiers.getJSONObject(i).getString("id")); + } else if (type.equals("eissn")) { + entry.setField("issn", identifiers.getJSONObject(i).getString("id")); + } + } + } + + // Links + if (bibJsonEntry.has("link")) { + JSONArray links = bibJsonEntry.getJSONArray("link"); + for (int i = 0; i < links.length(); i++) { + if (links.getJSONObject(i).has("type")) { + String type = links.getJSONObject(i).getString("type"); + if (type.equals("fulltext")) { + if (links.getJSONObject(i).has("url")) { + entry.setField("url", links.getJSONObject(i).getString("url")); + } + } + } + } + } + + return entry; + } +} diff --git a/src/main/resources/help/en/Contents.html b/src/main/resources/help/en/Contents.html index 9c97b45c7ef..84fbf88585c 100644 --- a/src/main/resources/help/en/Contents.html +++ b/src/main/resources/help/en/Contents.html @@ -57,6 +57,7 @@

Import/Export

  • Fetching entries from ACM Portal
  • Fetching entries from CiteSeerX
  • Fetching entries from DiVA
  • +
  • Fetching entries from DOAJ
  • Fetching entries using the DOI to BibTeX Converter
  • Fetching entries from Google Scholar
  • Fetching entries from IEEExplore
  • diff --git a/src/main/resources/help/en/DOAJHelp.html b/src/main/resources/help/en/DOAJHelp.html new file mode 100644 index 00000000000..3dcb269a2f9 --- /dev/null +++ b/src/main/resources/help/en/DOAJHelp.html @@ -0,0 +1,27 @@ + + + + + + +

    Fetching entries from DOAJ

    + +

    DOAJ (Directory of Open Access Journals) is a database + covering open access journals. + +

    To use this feature, choose Search -> Web search, and the + search interface will appear in the side pane. Select DOAJ (Directory of Open Access Journals) in the dropdown menu.

    + +

    Enter the text you want to search for in the search field + and press Enter or the Fetch button. + +

    It is possible to limit the search by adding a field name to the search, as field:text. The supported fields area +

    + + diff --git a/src/test/java/net/sf/jabref/importer/fileformat/JSONEntryParserTest.java b/src/test/java/net/sf/jabref/importer/fileformat/JSONEntryParserTest.java new file mode 100644 index 00000000000..52fb4364c98 --- /dev/null +++ b/src/test/java/net/sf/jabref/importer/fileformat/JSONEntryParserTest.java @@ -0,0 +1,53 @@ +/* Copyright (C) 2015 Oscar Gustafsson. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +package net.sf.jabref.importer.fileformat; + +import org.json.JSONObject; +import org.junit.Test; +import org.junit.Assert; + +import net.sf.jabref.model.entry.BibtexEntry; +import net.sf.jabref.model.entry.BibtexEntryTypes; + +public class JSONEntryParserTest { + + private final JSONEntryParser jc = new JSONEntryParser(); + @Test + public void testBibJSONConverter() { + String jsonString = new String( + "{\n\"title\": \"Design of Finite Word Length Linear-Phase FIR Filters in the Logarithmic Number System Domain\",\n" + + "\"journal\": {\n\"publisher\": \"Hindawi Publishing Corporation\",\n\"language\": [" + + "\"English\"],\n\"title\": \"VLSI Design\",\"country\": \"US\",\"volume\": \"2014\"" + + "},\"author\":[{\"name\": \"Syed Asad Alam\"},{\"name\": \"Oscar Gustafsson\"" + + "}\n],\n\"link\":[{\"url\": \"http://dx.doi.org/10.1155/2014/217495\"," + + "\"type\": \"fulltext\"}],\"year\":\"2014\",\"identifier\":[{" + + "\"type\": \"pissn\",\"id\": \"1065-514X\"},\n{\"type\": \"eissn\"," + + "\"id\": \"1563-5171\"},{\"type\": \"doi\",\"id\": \"10.1155/2014/217495\"" + + "}],\"created_date\":\"2014-05-09T19:38:31Z\"}\""); + JSONObject jo = new JSONObject(jsonString); + BibtexEntry be = jc.BibJSONtoBibtex(jo); + + Assert.assertEquals(BibtexEntryTypes.ARTICLE, be.getType()); + Assert.assertEquals("VLSI Design", be.getField("journal")); + Assert.assertEquals("10.1155/2014/217495", be.getField("doi")); + Assert.assertEquals("Syed Asad Alam and Oscar Gustafsson", be.getField("author")); + Assert.assertEquals( + "Design of Finite Word Length Linear-Phase FIR Filters in the Logarithmic Number System Domain", + be.getField("title")); + Assert.assertEquals("2014", be.getField("year")); + } +}