org.ambraproject.wombat.service.CitationDownloadServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.ambraproject.wombat.service.CitationDownloadServiceImpl.java

Source

/*
 * Copyright (c) 2017 Public Library of Science
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

package org.ambraproject.wombat.service;

import com.google.common.base.Strings;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CitationDownloadServiceImpl implements CitationDownloadService {

    /**
     * Return the fields of the author name, separated by commas, in a particular order.
     * <p>
     * Both the RIS and BibTex formats coincidentally use similar formats of the three name fields delimited by commas,
     * but place the fields in a different order.
     */
    private static String formatAuthorName(Map<String, String> authorData, String... fieldOrder) {
        return Stream.of(fieldOrder).map((String fieldKey) -> authorData.get(fieldKey))
                .filter((String namePart) -> !Strings.isNullOrEmpty(namePart)).collect(Collectors.joining(", "));
    }

    private static StringBuilder appendRisCitationLine(StringBuilder builder, String key, String value) {
        return builder.append(Objects.requireNonNull(key)).append("  - ").append(Strings.nullToEmpty(value))
                .append('\n');
    }

    private static String formatPublicationDate(Map<String, ?> articleMetadata, DateTimeFormatter formatter) {
        String dateString = (String) articleMetadata.get("publicationDate");
        LocalDate date = LocalDate.parse(dateString);
        return formatter.format(date);
    }

    private static String extractJournalTitle(Map<String, ?> articleMetadata) {
        Map<String, ?> journalMetadata = (Map<String, ?>) articleMetadata.get("journal");
        return (String) journalMetadata.get("title");
    }

    private static final DateTimeFormatter RIS_DATE_FORMAT = DateTimeFormatter.ofPattern("YYYY/MM/dd");

    @Override
    public String buildRisCitation(Map<String, ?> articleMetadata) {
        StringBuilder citation = new StringBuilder();
        appendRisCitationLine(citation, "TY", "JOUR");
        appendRisCitationLine(citation, "T1", XmlUtil.extractText((String) articleMetadata.get("title")));

        List<Map<String, String>> authors = (List<Map<String, String>>) articleMetadata.get("authors");
        for (Map<String, String> author : authors) {
            appendRisCitationLine(citation, "A1", formatAuthorName(author, "surnames", "givenNames", "suffix"));
        }

        String descriptionXml = (String) articleMetadata.get("description");
        String descriptionText = (descriptionXml == null) ? null : XmlUtil.extractText(descriptionXml);
        String journalTitle = extractJournalTitle(articleMetadata);

        appendRisCitationLine(citation, "Y1", formatPublicationDate(articleMetadata, RIS_DATE_FORMAT));
        appendRisCitationLine(citation, "N2", descriptionText);
        appendRisCitationLine(citation, "JF", journalTitle);
        appendRisCitationLine(citation, "JA", journalTitle);
        appendRisCitationLine(citation, "VL", (String) articleMetadata.get("volume"));
        appendRisCitationLine(citation, "IS", (String) articleMetadata.get("issue"));
        appendRisCitationLine(citation, "UR", (String) articleMetadata.get("url"));
        appendRisCitationLine(citation, "SP", (String) articleMetadata.get("eLocationId"));
        appendRisCitationLine(citation, "EP", null); // Always blank (copied from legacy implementation)
        appendRisCitationLine(citation, "PB", (String) articleMetadata.get("publisherName"));
        appendRisCitationLine(citation, "M3", "doi:" + articleMetadata.get("doi"));
        appendRisCitationLine(citation, "ER", null); // Always blank (copied from legacy implementation)

        return citation.toString();
    }

    private static enum BibtexField {
        AUTHOR("author", null) {
            @Override
            protected String extractValue(Map<String, ?> articleMetadata) {
                List<Map<String, String>> authors = (List<Map<String, String>>) articleMetadata.get("authors");
                return authors.stream()
                        .map(authorData -> formatAuthorName(authorData, "surnames", "suffix", "givenNames"))
                        .collect(Collectors.joining(" AND "));
            }
        },
        JOURNAL("journal", null) {
            @Override
            protected String extractValue(Map<String, ?> articleMetadata) {
                return extractJournalTitle(articleMetadata);
            }
        },
        PUBLISHER("publisher", "publisherName"), TITLE("title", "title") {
            @Override
            protected String extractValue(Map<String, ?> articleMetadata) {
                return XmlUtil.extractText(super.extractValue(articleMetadata));
            }
        },
        YEAR("year", null) {
            @Override
            protected String extractValue(Map<String, ?> articleMetadata) {
                return formatPublicationDate(articleMetadata, YEAR_FORMAT);
            }
        },
        MONTH("month", null) {
            @Override
            protected String extractValue(Map<String, ?> articleMetadata) {
                return formatPublicationDate(articleMetadata, MONTH_FORMAT);
            }
        },
        VOLUME("volume", "volume"), URL("url", "url"), PAGES("pages", null) {
            @Override
            protected String extractValue(Map<String, ?> articleMetadata) {
                Number pageCount = (Number) articleMetadata.get("pageCount");
                return (pageCount == null) ? null : ("1-" + pageCount.intValue());
            }
        },
        ABSTRACT("abstract", "description") {
            @Override
            protected String extractValue(Map<String, ?> articleMetadata) {
                String value = super.extractValue(articleMetadata);
                return (value == null) ? null : XmlUtil.extractText(value);
            }
        },
        NUMBER("number", "issue"), DOI("doi", "doi");

        private static final DateTimeFormatter YEAR_FORMAT = DateTimeFormatter.ofPattern("YYYY");
        private static final DateTimeFormatter MONTH_FORMAT = DateTimeFormatter.ofPattern("MM");

        private final String citationKey;
        private final String metadataKey;

        BibtexField(String citationKey, String metadataKey) {
            this.citationKey = Objects.requireNonNull(citationKey);
            this.metadataKey = metadataKey; // may be null if extractValue is overridden
        }

        protected String extractValue(Map<String, ?> articleMetadata) {
            return (String) articleMetadata.get(Objects.requireNonNull(metadataKey));
        }
    }

    @Override
    public String buildBibtexCitation(Map<String, ?> articleMetadata) {
        String doiName = (String) articleMetadata.get("doi");
        StringBuilder result = new StringBuilder();
        result.append("@article{").append(doiName).append(",\n");

        result.append(EnumSet.allOf(BibtexField.class).stream()
                .map(field -> String.format("    %s = {%s}", field.citationKey,
                        Strings.nullToEmpty(field.extractValue(articleMetadata))))
                .collect(Collectors.joining(",\n")));
        result.append("\n}");

        return result.toString();
    }

}