package org.jabref.logic.importer; import java.io.IOException; import java.nio.file.Path; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.SortedSet; import java.util.TreeSet; import org.jabref.logic.importer.fileformat.BibTeXMLImporter; import org.jabref.logic.importer.fileformat.BiblioscapeImporter; import org.jabref.logic.importer.fileformat.BibtexImporter; import org.jabref.logic.importer.fileformat.CopacImporter; import org.jabref.logic.importer.fileformat.CustomImporter; import org.jabref.logic.importer.fileformat.EndnoteImporter; import org.jabref.logic.importer.fileformat.FreeCiteImporter; import org.jabref.logic.importer.fileformat.InspecImporter; import org.jabref.logic.importer.fileformat.IsiImporter; import org.jabref.logic.importer.fileformat.MedlineImporter; import org.jabref.logic.importer.fileformat.MedlinePlainImporter; import org.jabref.logic.importer.fileformat.ModsImporter; import org.jabref.logic.importer.fileformat.MsBibImporter; import org.jabref.logic.importer.fileformat.OvidImporter; import org.jabref.logic.importer.fileformat.PdfContentImporter; import org.jabref.logic.importer.fileformat.PdfXmpImporter; import org.jabref.logic.importer.fileformat.RepecNepImporter; import org.jabref.logic.importer.fileformat.RisImporter; import org.jabref.logic.importer.fileformat.SilverPlatterImporter; import org.jabref.logic.l10n.Localization; import org.jabref.logic.xmp.XMPPreferences; import org.jabref.model.database.BibDatabases; import org.jabref.model.entry.BibEntry; import org.jabref.model.strings.StringUtil; public class ImportFormatReader { public static final String BIBTEX_FORMAT = "BibTeX"; /** * All import formats. * Sorted accordingly to {@link Importer#compareTo}, which defaults to alphabetically by the name */ private final SortedSet<Importer> formats = new TreeSet<>(); private ImportFormatPreferences importFormatPreferences; public void resetImportFormats(ImportFormatPreferences newImportFormatPreferences, XMPPreferences xmpPreferences) { this.importFormatPreferences = newImportFormatPreferences; formats.clear(); formats.add(new BiblioscapeImporter()); formats.add(new BibtexImporter(importFormatPreferences)); formats.add(new BibTeXMLImporter()); formats.add(new CopacImporter()); formats.add(new EndnoteImporter(importFormatPreferences)); formats.add(new FreeCiteImporter(importFormatPreferences)); formats.add(new InspecImporter()); formats.add(new IsiImporter()); formats.add(new MedlineImporter()); formats.add(new MedlinePlainImporter()); formats.add(new ModsImporter()); formats.add(new MsBibImporter()); formats.add(new OvidImporter()); formats.add(new PdfContentImporter(importFormatPreferences)); formats.add(new PdfXmpImporter(xmpPreferences)); formats.add(new RepecNepImporter(importFormatPreferences)); formats.add(new RisImporter()); formats.add(new SilverPlatterImporter()); // Get custom import formats for (CustomImporter importer : importFormatPreferences.getCustomImportList()) { formats.add(importer); } } /** * Format for a given CLI-ID. * <p> * <p>Will return the first format according to the default-order of * format that matches the given ID.</p> * * @param cliId CLI-Id * @return Import Format or <code>null</code> if none matches */ private Optional<Importer> getByCliId(String cliId) { for (Importer format : formats) { if (format.getId().equals(cliId)) { return Optional.of(format); } } return Optional.empty(); } public ParserResult importFromFile(String format, Path file) throws ImportException { Optional<Importer> importer = getByCliId(format); if (!importer.isPresent()) { throw new ImportException(Localization.lang("Unknown import format") + ": " + format); } try { return importer.get().importDatabase(file, importFormatPreferences.getEncoding()); } catch (IOException e) { throw new ImportException(e); } } /** * All importers. * <p> * <p> * Elements are in default order. * </p> * * @return all custom importers, elements are of type InputFormat */ public SortedSet<Importer> getImportFormats() { return this.formats; } /** * Human readable list of all known import formats (name and CLI Id). * <p> * <p>List is in default-order.</p> * * @return human readable list of all known import formats */ public String getImportFormatList() { StringBuilder sb = new StringBuilder(); for (Importer imFo : formats) { int pad = Math.max(0, 14 - imFo.getName().length()); sb.append(" "); sb.append(imFo.getName()); sb.append(StringUtil.repeatSpaces(pad)); sb.append(" : "); sb.append(imFo.getId()); sb.append('\n'); } return sb.toString(); } public static class UnknownFormatImport { public final String format; public final ParserResult parserResult; public UnknownFormatImport(String format, ParserResult parserResult) { this.format = format; this.parserResult = parserResult; } } /** * Tries to import a file by iterating through the available import filters, * and keeping the import that seems most promising. * <p/> * If all fails this method attempts to read this file as bibtex. * * @throws ImportException if the import fails (for example, if no suitable importer is found) */ public UnknownFormatImport importUnknownFormat(Path filePath) throws ImportException { Objects.requireNonNull(filePath); // First, see if it is a BibTeX file: try { ParserResult parserResult = OpenDatabase.loadDatabase(filePath.toFile(), importFormatPreferences); if (parserResult.getDatabase().hasEntries() || !parserResult.getDatabase().hasNoStrings()) { parserResult.setFile(filePath.toFile()); return new UnknownFormatImport(ImportFormatReader.BIBTEX_FORMAT, parserResult); } } catch (IOException ignore) { // Ignored } // stores ref to best result, gets updated at the next loop List<BibEntry> bestResult = null; int bestResultCount = 0; String bestFormatName = null; // Cycle through all importers: for (Importer imFo : getImportFormats()) { try { if (!imFo.isRecognizedFormat(filePath, importFormatPreferences.getEncoding())) { continue; } ParserResult parserResult = imFo.importDatabase(filePath, importFormatPreferences.getEncoding()); List<BibEntry> entries = parserResult.getDatabase().getEntries(); BibDatabases.purgeEmptyEntries(entries); int entryCount = entries.size(); if (entryCount > bestResultCount) { bestResult = entries; bestResultCount = bestResult.size(); bestFormatName = imFo.getName(); } } catch (IOException ex) { // The import did not succeed. Go on. } } if (bestResult != null) { // we found something ParserResult parserResult = new ParserResult(bestResult); parserResult.setFile(filePath.toFile()); return new UnknownFormatImport(bestFormatName, parserResult); } throw new ImportException(Localization.lang("Could not find a suitable import format.")); } }