org.dspace.identifier.ezid.EZIDRequest.java Source code

Java tutorial

Introduction

Here is the source code for org.dspace.identifier.ezid.EZIDRequest.java

Source

/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 * http://www.dspace.org/license/
 */
package org.dspace.identifier.ezid;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.HttpResponse;
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.HttpPut;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.dspace.identifier.DOI;
import org.dspace.identifier.IdentifierException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A request to EZID concerning a given (or expected) identifier.
 *
 * @author Mark H. Wood
 */
public class EZIDRequest {
    private static final Logger log = LoggerFactory.getLogger(EZIDRequest.class);

    private static final String ID_PATH = "/ezid/id/" + DOI.SCHEME;

    private static final String SHOULDER_PATH = "/ezid/shoulder/" + DOI.SCHEME;

    private static final String UTF_8 = "UTF-8";

    private static final String MD_KEY_STATUS = "_status";

    private final AbstractHttpClient client;

    private final String scheme;

    private final String host;

    private final String authority;

    /**
     * Prepare a context for requests concerning a specific identifier or
     * authority prefix.
     *
     * @param scheme URL scheme for access to the EZID service.
     * @param host Host name for access to the EZID service.
     * @param authority DOI authority prefix, e.g. "10.5072/FK2".
     * @param username an EZID user identity.
     * @param password user's password, or {@code null} for none.
     * @throws URISyntaxException if host or authority is bad.
     */
    EZIDRequest(String scheme, String host, String authority, String username, String password)
            throws URISyntaxException {
        this.scheme = scheme;

        this.host = host;

        if (authority.charAt(authority.length() - 1) == '/') {
            this.authority = authority.substring(0, authority.length() - 1);
        } else {
            this.authority = authority;
        }

        client = new DefaultHttpClient();
        if (null != username) {
            URI uri = new URI(scheme, host, null, null);
            client.getCredentialsProvider().setCredentials(new AuthScope(uri.getHost(), uri.getPort()),
                    new UsernamePasswordCredentials(username, password));
        }
    }

    /**
     * Fetch the metadata bound to an identifier.
     *
     * @throws IdentifierException if the response is error or body malformed.
     * @throws IOException if the HTTP request fails.
     * @throws URISyntaxException
     */
    public EZIDResponse lookup(String name) throws IdentifierException, IOException, URISyntaxException {
        // GET path
        HttpGet request;
        URI uri = new URI(scheme, host, ID_PATH + authority + name, null);
        log.debug("EZID lookup {}", uri.toASCIIString());
        request = new HttpGet(uri);
        HttpResponse response = client.execute(request);
        return new EZIDResponse(response);
    }

    /**
     * Create an identifier with a given name. The name is the end of the
     * request path. Note: to "reserve" a given identifier, include "_status =
     * reserved" in {@link metadata}.
     *
     * @param metadata ANVL-encoded key/value pairs.
     * @return
     */
    public EZIDResponse create(String name, Map<String, String> metadata)
            throws IOException, IdentifierException, URISyntaxException {
        // PUT path [+metadata]
        HttpPut request;
        URI uri = new URI(scheme, host, ID_PATH + authority + '/' + name, null);
        log.debug("EZID create {}", uri.toASCIIString());
        request = new HttpPut(uri);
        if (null != metadata) {
            try {
                request.setEntity(new StringEntity(formatMetadata(metadata), UTF_8));
            } catch (UnsupportedEncodingException ex) {
                /* SNH */ }
        }
        HttpResponse response = client.execute(request);
        return new EZIDResponse(response);
    }

    /**
     * Ask EZID to create a unique identifier and return its name. NOTE: to
     * "reserve" a unique identifier, include "_status = reserved" in {@link metadata}.
     *
     * @param metadata ANVL-encoded key/value pairs.
     * @return
     */
    public EZIDResponse mint(Map<String, String> metadata)
            throws IOException, IdentifierException, URISyntaxException {
        // POST path [+metadata]
        HttpPost request;
        URI uri = new URI(scheme, host, SHOULDER_PATH + authority, null);
        log.debug("EZID mint {}", uri.toASCIIString());
        request = new HttpPost(uri);
        if (null != metadata) {
            request.setEntity(new StringEntity(formatMetadata(metadata), UTF_8));
        }
        HttpResponse response = client.execute(request);
        EZIDResponse myResponse = new EZIDResponse(response);
        return myResponse;
    }

    /**
     * Alter the metadata bound to an identifier.
     *
     * @param metadata fields to be altered. Leave the value of a field's empty
     *                 to delete the field.
     * @return
     */
    public EZIDResponse modify(String name, Map<String, String> metadata)
            throws IOException, IdentifierException, URISyntaxException {
        if (null == metadata) {
            throw new IllegalArgumentException("metadata must not be null");
        }
        // POST path +metadata
        HttpPost request;
        URI uri = new URI(scheme, host, ID_PATH + authority + name, null);
        log.debug("EZID modify {}", uri.toASCIIString());
        request = new HttpPost(uri);
        request.setEntity(new StringEntity(formatMetadata(metadata), UTF_8));
        HttpResponse response = client.execute(request);
        return new EZIDResponse(response);
    }

    /**
     * Destroy a reserved identifier. Fails if ID was ever public.
     */
    public EZIDResponse delete(String name) throws IOException, IdentifierException, URISyntaxException {
        // DELETE path
        HttpDelete request;
        URI uri = new URI(scheme, host, ID_PATH + authority + name, null);
        log.debug("EZID delete {}", uri.toASCIIString());
        request = new HttpDelete(uri);
        HttpResponse response = client.execute(request);
        return new EZIDResponse(response);
    }

    /**
     * Remove a public identifier from view.
     */
    public EZIDResponse withdraw(String name) throws IOException, IdentifierException, URISyntaxException {
        Map<String, String> metadata = new HashMap<String, String>();
        metadata.put(MD_KEY_STATUS, "unavailable");
        return modify(name, metadata);
    }

    /**
     * Remove a public identifier from view, with a reason.
     *
     * @param reason annotation for the item's unavailability.
     */
    public EZIDResponse withdraw(String name, String reason)
            throws IOException, IdentifierException, URISyntaxException {
        Map<String, String> metadata = new HashMap<String, String>();
        metadata.put(MD_KEY_STATUS, "unavailable | " + escape(reason));
        return modify(name, metadata);
    }

    /**
     * Create ANVL-formatted name/value pairs from a Map.
     */
    private static String formatMetadata(Map<String, String> raw) {
        StringBuilder formatted = new StringBuilder();
        for (Entry<String, String> entry : raw.entrySet()) {
            formatted.append(escape(entry.getKey())).append(": ").append(escape(entry.getValue())).append('\n');
        }

        return formatted.toString();
    }

    /**
     * Percent-encode a few EZID-specific characters.
     *
     * @return null for null input.
     */
    private static String escape(String s) {
        if (null == s) {
            return s;
        }

        return s.replace("%", "%25").replace("\n", "%0A").replace("\r", "%0D").replace(":", "%3A");
    }
}