edu.lternet.pasta.doi.EzidRegistrar.java Source code

Java tutorial

Introduction

Here is the source code for edu.lternet.pasta.doi.EzidRegistrar.java

Source

/*
 *
 * Copyright 2011, 2012, 2013 the University of New Mexico.
 *
 * This work was supported by National Science Foundation Cooperative
 * Agreements #DEB-0832652 and #DEB-0936498.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 *
 */

package edu.lternet.pasta.doi;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
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.client.protocol.HttpClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import edu.lternet.pasta.datapackagemanager.ConfigurationListener;
import edu.ucsb.nceas.utilities.Options;

/**
 * @author servilla
 * @since Nov 17, 2012
 * 
 */
public class EzidRegistrar {

    /*
     * Class variables
     */

    private static final Logger logger = Logger.getLogger(edu.lternet.pasta.doi.EzidRegistrar.class);

    private static final String dirPath = "WebRoot/WEB-INF/conf";

    /*
     * Instance variables
     */

    private DataCiteMetadata dataCiteMetadata = null;

    private String host = null;
    private String port = null;
    private String protocol = null;

    private String ezidUser = null;
    private String ezidPassword = null;
    private String keystore = null;
    private String keystorePassword = null;

    private String sessionId = null;

    /*
     * Constructors
     */

    public EzidRegistrar() throws ConfigurationException {

        Options options = null;
        options = ConfigurationListener.getOptions();

        if (options == null) {
            ConfigurationListener configurationListener = new ConfigurationListener();
            configurationListener.initialize(dirPath);
            options = ConfigurationListener.getOptions();
        }

        this.loadOptions(options);

    }

    /*
     * Class methods
     */

    /*
     * Instance methods
     */

    /*
     * Closes the HTTP client
     */
    private void closeHttpClient(CloseableHttpClient httpClient) {
        try {
            httpClient.close();
        } catch (IOException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * Loads Data Manager options from a configuration file.
     * 
     * @param options Configuration options object.
     * @throws ConfigurationException
     */
    private void loadOptions(Options options) throws ConfigurationException {

        if (options != null) {

            this.host = options.getOption("datapackagemanager.ezidHost");
            this.port = options.getOption("datapackagemanager.ezidPort");
            this.protocol = options.getOption("datapackagemanager.ezidProtocol");
            this.ezidUser = options.getOption("datapackagemanager.ezidUser");
            this.ezidPassword = options.getOption("datapackagemanager.ezidPassword");

        } else {
            throw new ConfigurationException("Configuration options failed to load");
        }

    }

    /**
     * Sets the DataCite metadata object.
     * 
     * @param dataCiteMetadata
     */
    public void setDataCiteMetadata(DataCiteMetadata dataCiteMetadata) {
        this.dataCiteMetadata = dataCiteMetadata;
    }

    /**
     * Gets the DataCite metadata object.
     * 
     * @return DataCite metadata object
     */
    public DataCiteMetadata getDataCiteMetadata() {
        return this.dataCiteMetadata;
    }

    /**
     * Login to the EZID web service API system and return a valid session
     * identifier.
     * 
     * @return The EZID session id
     * @throws EzidException
     */
    public void login() throws EzidException {

        String sessionId = null;

        /*
         * The following set of code sets up Preemptive Authentication for the HTTP
         * CLIENT and is done so at the warning stated within the Apache
         * Http-Components Client tutorial here:
         * http://hc.apache.org/httpcomponents-
         * client-ga/tutorial/html/authentication.html#d5e1031
         */

        HttpHost httpHost = new HttpHost(this.host, Integer.valueOf(this.port), this.protocol);
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        AuthScope authScope = new AuthScope(httpHost.getHostName(), httpHost.getPort());
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(this.ezidUser, this.ezidPassword);
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(authScope, credentials);

        // Create AuthCache instance
        AuthCache authCache = new BasicAuthCache();

        // Generate BASIC scheme object and add it to the auth cache
        BasicScheme basicAuth = new BasicScheme();
        authCache.put(httpHost, basicAuth);

        // Add AuthCache to the execution context
        HttpClientContext context = HttpClientContext.create();
        context.setCredentialsProvider(credentialsProvider);
        context.setAuthCache(authCache);

        HttpGet httpGet = new HttpGet(this.getEzidUrl("/login"));

        HttpResponse response = null;
        Header[] headers = null;
        Integer statusCode = null;

        try {

            response = httpClient.execute(httpHost, httpGet, context);
            headers = response.getAllHeaders();
            statusCode = (Integer) response.getStatusLine().getStatusCode();
            logger.info("STATUS: " + statusCode.toString());

        } catch (UnsupportedEncodingException e) {
            logger.error(e);
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            logger.error(e);
            e.printStackTrace();
        } catch (IOException e) {
            logger.error(e);
            e.printStackTrace();
        } finally {
            closeHttpClient(httpClient);
        }

        if (statusCode == HttpStatus.SC_OK) {

            String headerName = null;
            String headerValue = null;

            // Loop through all headers looking for the "Set-Cookie" header.
            for (int i = 0; i < headers.length; i++) {
                headerName = headers[i].getName();

                if (headerName.equals("Set-Cookie")) {
                    headerValue = headers[i].getValue();
                    sessionId = this.getSessionId(headerValue);
                    logger.info("Session: " + sessionId);
                }

            }

        } else {
            String gripe = "login: failed EZID login.";
            throw new EzidException(gripe);
        }

        this.sessionId = sessionId;

    }

    /**
     * Logout of the EZID service session.
     * 
     * @throws EzidException
     */
    public void logout() throws EzidException {

        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        String url = this.getEzidUrl("/logout");
        HttpGet httpGet = new HttpGet(url);
        String entityString = null;
        Integer statusCode = null;

        // Set header content
        if (this.sessionId != null) {
            httpGet.setHeader("Cookie", "sessionid=" + this.sessionId);
        }

        try {

            HttpResponse httpResponse = httpClient.execute(httpGet);
            statusCode = httpResponse.getStatusLine().getStatusCode();
            HttpEntity httpEntity = httpResponse.getEntity();
            entityString = EntityUtils.toString(httpEntity);

        } catch (ClientProtocolException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } finally {
            closeHttpClient(httpClient);
        }

        if (statusCode != HttpStatus.SC_OK) {
            String gripe = "Failed to logout of EZID cleanly.";
            throw new EzidException(gripe);
        }

        logger.info("logout: " + entityString);

    }

    /**
     * Registers the resource DOI based on the DataCite metadata object.
     * 
     * @throws EzidException
     */
    public void registerDataCiteMetadata() throws EzidException {

        if (this.dataCiteMetadata == null) {
            String gripe = "registerDataCiteMetadata: DataCite metadata object is null.";
            throw new EzidException(gripe);
        }

        HttpHost httpHost = new HttpHost(this.host, Integer.valueOf(this.port), this.protocol);
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        AuthScope authScope = new AuthScope(httpHost.getHostName(), httpHost.getPort());
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(this.ezidUser, this.ezidPassword);
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(authScope, credentials);

        // Create AuthCache instance
        AuthCache authCache = new BasicAuthCache();

        // Generate BASIC scheme object and add it to the local auth cache
        BasicScheme basicAuth = new BasicScheme();
        authCache.put(httpHost, basicAuth);

        // Add AuthCache to the execution context
        HttpClientContext context = HttpClientContext.create();
        context.setCredentialsProvider(credentialsProvider);
        context.setAuthCache(authCache);

        String doi = this.dataCiteMetadata.getDigitalObjectIdentifier().getDoi();
        String url = this.getEzidUrl("/id/" + doi);
        StringBuffer metadata = new StringBuffer("");
        metadata.append("datacite: " + this.dataCiteMetadata.toDataCiteXml() + "\n");
        metadata.append("_target: " + this.dataCiteMetadata.getLocationUrl() + "\n");
        HttpPut httpPut = new HttpPut(url);
        httpPut.setHeader("Content-type", "text/plain");
        HttpEntity stringEntity = null;
        Integer statusCode = null;
        String entityString = null;

        try {
            stringEntity = new StringEntity(metadata.toString());
            httpPut.setEntity(stringEntity);
            HttpResponse httpResponse = httpClient.execute(httpHost, httpPut, context);
            statusCode = httpResponse.getStatusLine().getStatusCode();
            HttpEntity httpEntity = httpResponse.getEntity();
            entityString = EntityUtils.toString(httpEntity);
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } finally {
            closeHttpClient(httpClient);
        }

        logger.info("registerDataCiteMetadata: " + this.dataCiteMetadata.getLocationUrl() + "\n" + entityString);

        // Test for DOI collision or DOI registration failure
        if ((statusCode == HttpStatus.SC_BAD_REQUEST) && (entityString != null)
                && (entityString.contains("identifier already exists"))) {
            String gripe = "identifier already exists";
            throw new EzidException(gripe);
        } else if (statusCode != HttpStatus.SC_CREATED) {
            logger.error(this.dataCiteMetadata.toDataCiteXml());
            String gripe = "DOI registration failed for: " + doi;
            throw new EzidException(gripe);
        }

    }

    /**
     * Make the DOI obsolete by setting the EZID metadata field "_status" to
     * "unavailable".
     * 
     * @param doi The DOI to obsolete
     * @throws EzidException
     */
    public void obsoleteDoi(String doi) throws EzidException {

        HttpHost httpHost = new HttpHost(this.host, Integer.valueOf(this.port), this.protocol);
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        AuthScope authScope = new AuthScope(httpHost.getHostName(), httpHost.getPort());
        UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(this.ezidUser, this.ezidPassword);
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(authScope, credentials);

        // Create AuthCache instance
        AuthCache authCache = new BasicAuthCache();

        // Generate BASIC scheme object and add it to the local auth cache
        BasicScheme basicAuth = new BasicScheme();
        authCache.put(httpHost, basicAuth);

        // Add AuthCache to the execution context
        HttpClientContext context = HttpClientContext.create();
        context.setCredentialsProvider(credentialsProvider);
        context.setAuthCache(authCache);

        String url = this.getEzidUrl("/id/" + doi);

        StringBuffer metadata = new StringBuffer("");
        metadata.append("_status: unavailable | withdrawn by author\n");

        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Content-type", "text/plain");
        HttpEntity stringEntity = null;
        Integer statusCode = null;
        String entityString = null;

        try {
            stringEntity = new StringEntity(metadata.toString());
            httpPost.setEntity(stringEntity);
            HttpResponse httpResponse = httpClient.execute(httpHost, httpPost, context);
            statusCode = httpResponse.getStatusLine().getStatusCode();
            HttpEntity httpEntity = httpResponse.getEntity();
            entityString = EntityUtils.toString(httpEntity);
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        } finally {
            closeHttpClient(httpClient);
        }

        logger.info("obsoleteDoi: " + entityString);

        if (statusCode != HttpStatus.SC_OK) {
            String gripe = "DOI obsoletion failed for: " + doi;
            throw new EzidException(gripe);
        }

    }

    /**
     * Parse the "Set-Cookie" header looking for the "sessionid" key-value pair
     * and return the session identifier.
     * 
     * @param setCookieHeader
     *          The full "Set-Cookie" header.
     * 
     * @return The session identifier
     */
    private String getSessionId(String setCookieHeader) {

        String sessionId = null;

        String[] headerParts = setCookieHeader.split(";");

        for (int i = 0; i < headerParts.length; i++) {

            // Extract token value from the key-value pair.
            if (headerParts[i].startsWith("sessionid=")) {
                int start = "sessionid=".length();
                int end = headerParts[i].length() - 1;
                sessionId = headerParts[i].substring(start, end);
            }

        }

        return sessionId;

    }

    /**
     * Builds full URL to EZID services.
     * 
     * @param url
     *          The EZID URL path
     * @return The full URL
     */
    private String getEzidUrl(String url) {
        return this.protocol + "://" + this.host + url;
    }

    /**
     * Gets the EZID service session identifier.
     * 
     * @return EZID service session identifier
     */
    private String getSessionId() {
        return this.sessionId;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {

        EzidRegistrar ezidRegistrar = null;

        try {
            ezidRegistrar = new EzidRegistrar();
            ezidRegistrar.obsoleteDoi("doi:10.6073/pasta/dcbd7c1aab57af6a65672aa917bb3faf");
        } catch (Exception e) {
            logger.error(e.getMessage());
            e.printStackTrace();
        }

    }

}