org.fao.geonet.doi.client.DoiClient.java Source code

Java tutorial

Introduction

Here is the source code for org.fao.geonet.doi.client.DoiClient.java

Source

//=============================================================================
//===   Copyright (C) 2001-2010 Food and Agriculture Organization of the
//===   United Nations (FAO-UN), United Nations World Food Programme (WFP)
//===   and United Nations Environment Programme (UNEP)
//===
//===   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 St, Fifth Floor, Boston, MA 02110-1301, USA
//===
//===   Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
//===   Rome - Italy. email: geonetwork@osgeo.org
//==============================================================================
package org.fao.geonet.doi.client;

import com.google.common.io.CharStreams;
import org.apache.commons.io.IOUtils;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.fao.geonet.ApplicationContextHolder;
import org.fao.geonet.utils.GeonetHttpRequestFactory;
import org.fao.geonet.utils.Log;
import org.apache.commons.httpclient.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.client.ClientHttpResponse;

import java.io.InputStreamReader;
import java.text.MessageFormat;

import static org.fao.geonet.doi.client.DoiSettings.LOGGER_NAME;

/**
 * Doi API client.
 *
 * See https://mds.datacite.org/static/apidoc.
 *
 * @author Jose Garca
 */
public class DoiClient {

    public static final String DOI_ENTITY = "DOI";
    public static final String ALL_DOI_ENTITY = "All DOI";
    public static final String DOI_METADATA_ENTITY = "DOI metadata";
    private String serverUrl;
    private String username;
    private String password;

    private boolean testMode;

    protected GeonetHttpRequestFactory requestFactory;

    public DoiClient(String serverUrl, String username, String password) {
        this(serverUrl, username, password, true);
    }

    public DoiClient(String serverUrl, String username, String password, boolean testMode) {
        this.serverUrl = serverUrl.endsWith("/") ? serverUrl : serverUrl + "/";
        this.username = username;
        this.password = password;
        this.testMode = testMode;

        requestFactory = ApplicationContextHolder.get().getBean(GeonetHttpRequestFactory.class);
    }

    /**
     * POST will mint new DOI if specified DOI doesn't exist.
     * This method will attempt to update URL if you specify existing DOI.
     * Standard domains and quota restrictions check will be performed.
     * Datacentre's doiQuotaUsed will be increased by 1. A new record in Datasets will be created.
     *
     * @param doi   The DOI prefix for the datacenter / identifier eg. 10.5072/TEST-1
     * @param url   The landing page
     * @throws DoiClientException
     */
    public void createDoi(String doi, String url) throws DoiClientException {

        String requestBody = MessageFormat.format("doi={0}\nurl={1}", doi, url);

        create(createUrl("doi"), requestBody, "text/plain;charset=UTF-8", DOI_ENTITY);
    }

    /**
     * This request returns an URL associated with a given DOI.
     *
     * @param doi
     * @return If response status is 200: URL representing a dataset;
     *          empty for 204;
     *          null for not found;
     *          otherwise short explanation for non-200 status.
     * @throws DoiClientException
     */
    public String retrieveDoi(String doi) throws DoiClientException {

        return retrieve(createUrl("doi/" + doi), DOI_ENTITY);
    }

    /**
     * This request returns a list of all DOIs for the requesting datacentre.
     * There is no guaranteed order.
     *
     * @param doi
     * @return If response status is 200: list of DOIs, one DOI per line; empty for 204.
     * @throws DoiClientException
     */
    public String retrieveAllDoi(String doi) throws DoiClientException {

        return retrieve(createUrl("doi"), ALL_DOI_ENTITY);
    }

    /**
     * This request stores new version of metadata.
     * The request body must contain valid XML.
     *
     *
     * @param doi eg. 10.5072/JQX3-61AT
     * @param doiMetadata XML in DataCite format as String
     * @throws DoiClientException
     */
    public void createDoiMetadata(String doi, String doiMetadata) throws DoiClientException {

        //        create(createUrl("metadata/" + doi),
        create(createUrl("metadata"), doiMetadata, "application/xml", DOI_METADATA_ENTITY);
    }

    /**
     * This request returns the most recent version of metadata associated with a given DOI.
     *
     * @param doi
     * @return
     * @throws DoiClientException
     */
    public String retrieveDoiMetadata(String doi) throws DoiClientException {
        return retrieve(createUrl("metadata/" + doi), "DOI metadata");
    }

    /**
     * This request marks a dataset as 'inactive'.
     * To activate it again, POST new metadata or set the isActive-flag in the user interface.
     *
     * @param doi
     * @throws DoiClientException
     */
    public void deleteDoiMetadata(String doi) throws DoiClientException {

        ClientHttpResponse httpResponse = null;
        HttpDelete deleteMethod = null;

        try {
            Log.debug(LOGGER_NAME, "   -- URL: " + this.serverUrl + "/metadata");

            deleteMethod = new HttpDelete(createUrl("metadata/" + doi));

            httpResponse = requestFactory.execute(deleteMethod, new UsernamePasswordCredentials(username, password),
                    AuthScope.ANY);
            int status = httpResponse.getRawStatusCode();

            Log.debug(LOGGER_NAME, "   -- Request status code: " + status);

            // Ignore NOT FOUND (trying to delete a non existing doi metadata)
            if ((status != HttpStatus.SC_NOT_FOUND) && (status != HttpStatus.SC_OK)) {
                Log.info(LOGGER_NAME, "Delete DOI metadata end -- Error: " + httpResponse.getStatusText());

                throw new DoiClientException(httpResponse.getStatusText());
            } else {
                Log.info(LOGGER_NAME, "DeleteDOI metadata end");
            }

        } catch (Exception ex) {
            Log.error(LOGGER_NAME, "   -- Error (exception): " + ex.getMessage());
            throw new DoiClientException(ex.getMessage());

        } finally {
            if (deleteMethod != null) {
                deleteMethod.releaseConnection();
            }
            // Release the connection.
            IOUtils.closeQuietly(httpResponse);
        }
    }

    public void deleteDoi(String doi) throws DoiClientException {

        ClientHttpResponse httpResponse = null;
        HttpDelete deleteMethod = null;

        try {
            Log.debug(LOGGER_NAME, "   -- URL: " + this.serverUrl + "/metadata");

            deleteMethod = new HttpDelete(createUrl("doi/" + doi));

            httpResponse = requestFactory.execute(deleteMethod, new UsernamePasswordCredentials(username, password),
                    AuthScope.ANY);
            int status = httpResponse.getRawStatusCode();

            Log.debug(LOGGER_NAME, "   -- Request status code: " + status);

            // Ignore NOT FOUND (trying to delete a non existing doi metadata)
            if ((status != HttpStatus.SC_NOT_FOUND) && (status != HttpStatus.SC_OK)) {
                Log.info(LOGGER_NAME, "Delete DOI end -- Error: " + httpResponse.getStatusText());

                throw new DoiClientException(httpResponse.getStatusText());
            } else {
                Log.info(LOGGER_NAME, "DeleteDOI end");
            }

        } catch (Exception ex) {
            Log.error(LOGGER_NAME, "   -- Error (exception): " + ex.getMessage());
            throw new DoiClientException(ex.getMessage());

        } finally {
            if (deleteMethod != null) {
                deleteMethod.releaseConnection();
            }
            // Release the connection.
            IOUtils.closeQuietly(httpResponse);
        }
    }

    /**
     * See https://support.datacite.org/docs/mds-api-guide#section-register-metadata
     */
    private void create(String url, String body, String contentType, String entity) throws DoiClientException {

        ClientHttpResponse httpResponse = null;
        HttpPost postMethod = null;

        try {
            Log.debug(LOGGER_NAME, "   -- URL: " + url);

            postMethod = new HttpPost(url);

            ((HttpUriRequest) postMethod)
                    .addHeader(new BasicHeader("Content-Type", contentType + ";charset=UTF-8"));
            Log.debug(LOGGER_NAME, "   -- Request body: " + body);

            StringEntity requestEntity = new StringEntity(body, contentType, "UTF-8");

            postMethod.setEntity(requestEntity);

            httpResponse = requestFactory.execute(postMethod, new UsernamePasswordCredentials(username, password),
                    AuthScope.ANY);
            int status = httpResponse.getRawStatusCode();

            Log.debug(LOGGER_NAME, "   -- Request status code: " + status);

            if (status != HttpStatus.SC_CREATED) {
                String message = String.format("Failed to create '%s' with '%s'. Status is %d. Error is %s.", url,
                        body, status, httpResponse.getStatusText());

                Log.info(LOGGER_NAME, message);
                throw new DoiClientException(message);
            } else {
                Log.info(LOGGER_NAME, String.format("DOI metadata created at %s.", url));
            }
        } catch (Exception ex) {
            Log.error(LOGGER_NAME, "   -- Error (exception): " + ex.getMessage());
            throw new DoiClientException(ex.getMessage());

        } finally {
            if (postMethod != null) {
                postMethod.releaseConnection();
            }
            // Release the connection.
            IOUtils.closeQuietly(httpResponse);
        }
    }

    private String retrieve(String url, String entity) throws DoiClientException {

        ClientHttpResponse httpResponse = null;
        HttpGet getMethod = null;

        try {
            Log.debug(LOGGER_NAME, "   -- URL: " + url);

            getMethod = new HttpGet(url);

            httpResponse = requestFactory.execute(getMethod, new UsernamePasswordCredentials(username, password),
                    AuthScope.ANY);
            int status = httpResponse.getRawStatusCode();

            Log.debug(LOGGER_NAME, "   -- Request status code: " + status);

            if (status == HttpStatus.SC_OK) {
                return CharStreams.toString(new InputStreamReader(httpResponse.getBody()));
            } else if (status == HttpStatus.SC_NO_CONTENT) {
                return null; // Not found
            } else if (status == HttpStatus.SC_NOT_FOUND) {
                return null; // Not found
            } else {
                Log.info(LOGGER_NAME, "Retrieve DOI metadata end -- Error: " + httpResponse.getStatusText());

                throw new DoiClientException(httpResponse.getStatusText()
                        + CharStreams.toString(new InputStreamReader(httpResponse.getBody())));
            }

        } catch (Exception ex) {
            Log.error(LOGGER_NAME, "   -- Error (exception): " + ex.getMessage());
            throw new DoiClientException(ex.getMessage());

        } finally {
            if (getMethod != null) {
                getMethod.releaseConnection();
            }
            // Release the connection.
            IOUtils.closeQuietly(httpResponse);
        }
    }

    /**
     * Builds service url with server url.
     *
     * @param service
     * @return
     */
    private String createUrl(String service) {
        return this.serverUrl + (this.serverUrl.endsWith("/") ? "" : "/") + service;
    }
}