Java tutorial
/** * 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"); } }