org.dspace.identifier.doi.DOIOrganiser.java Source code

Java tutorial

Introduction

Here is the source code for org.dspace.identifier.doi.DOIOrganiser.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.doi;

import org.apache.commons.cli.*;
import org.apache.log4j.Logger;
import org.dspace.content.DSpaceObject;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.*;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
import org.dspace.identifier.DOI;
import org.dspace.identifier.DOIIdentifierProvider;
import org.dspace.identifier.IdentifierException;
import org.dspace.identifier.factory.IdentifierServiceFactory;
import org.dspace.identifier.service.DOIService;
import org.dspace.utils.DSpace;

import java.io.IOException;
import java.io.PrintStream;
import java.sql.SQLException;
import java.util.*;

/**
 *
 * @author Marsa Haoua
 * @author Pascal-Nicolas Becker
 */
public class DOIOrganiser {

    private static final Logger LOG = Logger.getLogger(DOIOrganiser.class);

    private DOIIdentifierProvider provider;
    private Context context;
    private boolean quiet;
    protected HandleService handleService;
    protected ItemService itemService;
    protected DOIService doiService;

    public DOIOrganiser(Context context, DOIIdentifierProvider provider) {
        this.context = context;
        this.provider = provider;
        this.quiet = false;
        this.handleService = HandleServiceFactory.getInstance().getHandleService();
        this.itemService = ContentServiceFactory.getInstance().getItemService();
        this.doiService = IdentifierServiceFactory.getInstance().getDOIService();
    }

    public static void main(String[] args) {
        LOG.debug("Starting DOI organiser ");

        // setup Context
        Context context = new Context();

        // Started from commandline, don't use the authentication system.
        context.turnOffAuthorisationSystem();

        DOIOrganiser organiser = new DOIOrganiser(context,
                new DSpace().getSingletonService(DOIIdentifierProvider.class));

        // run command line interface
        runCLI(context, organiser, args);

        try {
            context.complete();
        } catch (SQLException sqle) {
            System.err.println("Cannot save changes to database: " + sqle.getMessage());
            System.exit(-1);
        }

    }

    public static void runCLI(Context context, DOIOrganiser organiser, String[] args) {
        // initlize options
        Options options = new Options();

        options.addOption("h", "help", false, "Help");
        options.addOption("l", "list", false, "List all objects to be reserved, registered, deleted of updated ");
        options.addOption("r", "register-all", false,
                "Perform online registration for all identifiers queued for registration.");
        options.addOption("s", "reserve-all", false,
                "Perform online reservation for all identifiers queued for reservation.");
        options.addOption("u", "update-all", false,
                "Perform online metadata update for all identifiers queued for metadata update.");
        options.addOption("d", "delete-all", false,
                "Perform online deletion for all identifiers queued for deletion.");

        options.addOption("q", "quiet", false, "Turn the command line output off.");

        Option registerDoi = OptionBuilder.withArgName("DOI|ItemID|handle").withLongOpt("register-doi").hasArgs(1)
                .withDescription("Register a specified identifier. "
                        + "You can specify the identifier by ItemID, Handle or DOI.")
                .create();

        options.addOption(registerDoi);

        Option reserveDoi = OptionBuilder.withArgName("DOI|ItemID|handle").withLongOpt("reserve-doi").hasArgs(1)
                .withDescription("Reserve a specified identifier online. "
                        + "You can specify the identifier by ItemID, Handle or DOI.")
                .create();

        options.addOption(reserveDoi);

        Option update = OptionBuilder.withArgName("DOI|ItemID|handle").hasArgs(1)
                .withDescription("Update online an object for a given DOI identifier"
                        + " or ItemID or Handle. A DOI identifier or an ItemID or a Handle is needed.\n")
                .withLongOpt("update-doi").create();

        options.addOption(update);

        Option delete = OptionBuilder.withArgName("DOI identifier").withLongOpt("delete-doi").hasArgs(1)
                .withDescription("Delete a specified identifier.").create();

        options.addOption(delete);

        // initialize parser
        CommandLineParser parser = new PosixParser();
        CommandLine line = null;
        HelpFormatter helpformater = new HelpFormatter();

        try {
            line = parser.parse(options, args);
        } catch (ParseException ex) {
            LOG.fatal(ex);
            System.exit(1);
        }

        // process options
        // user asks for help
        if (line.hasOption('h') || 0 == line.getOptions().length) {
            helpformater.printHelp("\nDOI organiser\n", options);
        }

        if (line.hasOption('q')) {
            organiser.setQuiet();
        }

        if (line.hasOption('l')) {
            organiser.list("reservation", null, null, DOIIdentifierProvider.TO_BE_RESERVED);
            organiser.list("registration", null, null, DOIIdentifierProvider.TO_BE_REGISTERED);
            organiser.list("update", null, null, DOIIdentifierProvider.UPDATE_BEFORE_REGISTRATION,
                    DOIIdentifierProvider.UPDATE_REGISTERED, DOIIdentifierProvider.UPDATE_RESERVED);
            organiser.list("deletion", null, null, DOIIdentifierProvider.TO_BE_DELETED);
        }

        DOIService doiService = IdentifierServiceFactory.getInstance().getDOIService();

        if (line.hasOption('s')) {

            try {
                List<DOI> dois = doiService.getDOIsByStatus(context,
                        Arrays.asList(DOIIdentifierProvider.TO_BE_RESERVED));
                if (0 == dois.size()) {
                    System.err.println("There are no objects in the database " + "that could be reserved.");
                }

                for (DOI doi : dois) {
                    organiser.reserve(doi);
                    context.uncacheEntity(doi);
                }
            } catch (SQLException ex) {
                System.err.println("Error in database connection:" + ex.getMessage());
                ex.printStackTrace(System.err);
            }
        }

        if (line.hasOption('r')) {

            try {
                List<DOI> dois = doiService.getDOIsByStatus(context,
                        Arrays.asList(DOIIdentifierProvider.TO_BE_REGISTERED));
                if (0 == dois.size()) {
                    System.err.println("There are no objects in the database " + "that could be registered.");
                }
                for (DOI doi : dois) {
                    organiser.register(doi);
                    context.uncacheEntity(doi);
                }
            } catch (SQLException ex) {
                System.err.println("Error in database connection:" + ex.getMessage());
                ex.printStackTrace(System.err);
            }
        }

        if (line.hasOption('u')) {

            try {
                List<DOI> dois = doiService.getDOIsByStatus(context,
                        Arrays.asList(DOIIdentifierProvider.UPDATE_BEFORE_REGISTRATION,
                                DOIIdentifierProvider.UPDATE_RESERVED, DOIIdentifierProvider.UPDATE_REGISTERED));
                if (0 == dois.size()) {
                    System.err.println("There are no objects in the database " + "whose metadata needs an update.");
                }

                for (DOI doi : dois) {
                    organiser.update(doi);
                    context.uncacheEntity(doi);
                }
            } catch (SQLException ex) {
                System.err.println("Error in database connection:" + ex.getMessage());
                ex.printStackTrace(System.err);
            }
        }

        if (line.hasOption('d')) {

            try {
                List<DOI> dois = doiService.getDOIsByStatus(context,
                        Arrays.asList(DOIIdentifierProvider.TO_BE_DELETED));
                if (0 == dois.size()) {
                    System.err.println("There are no objects in the database " + "that could be deleted.");
                }

                Iterator<DOI> iterator = dois.iterator();
                while (iterator.hasNext()) {
                    DOI doi = iterator.next();
                    iterator.remove();
                    organiser.delete(doi.getDoi());
                    context.uncacheEntity(doi);
                }
            } catch (SQLException ex) {
                System.err.println("Error in database connection:" + ex.getMessage());
                ex.printStackTrace(System.err);
            }
        }

        if (line.hasOption("reserve-doi")) {
            String identifier = line.getOptionValue("reserve-doi");

            if (null == identifier) {
                helpformater.printHelp("\nDOI organiser\n", options);
            } else {
                try {
                    DOI doiRow = organiser.resolveToDOI(identifier);
                    organiser.reserve(doiRow);
                } catch (SQLException ex) {
                    LOG.error(ex);
                } catch (IllegalArgumentException ex) {
                    LOG.error(ex);
                } catch (IllegalStateException ex) {
                    LOG.error(ex);
                } catch (IdentifierException ex) {
                    LOG.error(ex);
                }
            }
        }

        if (line.hasOption("register-doi")) {
            String identifier = line.getOptionValue("register-doi");

            if (null == identifier) {
                helpformater.printHelp("\nDOI organiser\n", options);
            } else {
                try {
                    DOI doiRow = organiser.resolveToDOI(identifier);
                    organiser.register(doiRow);
                } catch (SQLException ex) {
                    LOG.error(ex);
                } catch (IllegalArgumentException ex) {
                    LOG.error(ex);
                } catch (IllegalStateException ex) {
                    LOG.error(ex);
                } catch (IdentifierException ex) {
                    LOG.error(ex);
                }
            }
        }

        if (line.hasOption("update-doi")) {
            String identifier = line.getOptionValue("update-doi");

            if (null == identifier) {
                helpformater.printHelp("\nDOI organiser\n", options);
            } else {
                try {
                    DOI doiRow = organiser.resolveToDOI(identifier);
                    organiser.update(doiRow);
                } catch (SQLException ex) {
                    LOG.error(ex);
                } catch (IllegalArgumentException ex) {
                    LOG.error(ex);
                } catch (IllegalStateException ex) {
                    LOG.error(ex);
                } catch (IdentifierException ex) {
                    LOG.error(ex);
                }
            }
        }

        if (line.hasOption("delete-doi")) {
            String identifier = line.getOptionValue("delete-doi");

            if (null == identifier) {
                helpformater.printHelp("\nDOI organiser\n", options);
            } else {
                try {
                    organiser.delete(identifier);
                } catch (SQLException ex) {
                    LOG.error(ex);
                } catch (IllegalArgumentException ex) {
                    LOG.error(ex);
                }
            }
        }

    }

    public void list(String processName, PrintStream out, PrintStream err, Integer... status) {
        String indent = "    ";
        if (null == out) {
            out = System.out;
        }
        if (null == err) {
            err = System.err;
        }

        try {
            List<DOI> doiList = doiService.getDOIsByStatus(context, Arrays.asList(status));
            if (0 < doiList.size()) {
                out.println("DOIs queued for " + processName + ": ");
            } else {
                out.println("There are no DOIs queued for " + processName + ".");
            }
            for (DOI doiRow : doiList) {
                out.print(indent + DOI.SCHEME + doiRow.getDoi());
                DSpaceObject dso = doiRow.getDSpaceObject();
                if (null != dso) {
                    out.println(" (belongs to item with handle " + dso.getHandle() + ")");
                } else {
                    out.println(" (cannot determine handle of assigned object)");
                }
            }
            out.println("");
        } catch (SQLException ex) {
            err.println("Error in database Connection: " + ex.getMessage());
            ex.printStackTrace(err);
        }
    }

    public void register(DOI doiRow) throws SQLException {
        DSpaceObject dso = doiRow.getDSpaceObject();
        if (Constants.ITEM != dso.getType()) {
            throw new IllegalArgumentException("Currenty DSpace supports DOIs for Items only.");
        }

        try {
            provider.registerOnline(context, dso, DOI.SCHEME + doiRow.getDoi());

            if (!quiet) {
                System.out.println(
                        "This identifier: " + DOI.SCHEME + doiRow.getDoi() + " is successfully registered.");
            }
        } catch (IdentifierException ex) {
            if (!(ex instanceof DOIIdentifierException)) {
                LOG.error("It wasn't possible to register this identifier: " + DOI.SCHEME + doiRow.getDoi()
                        + " online. ", ex);
            }

            DOIIdentifierException doiIdentifierException = (DOIIdentifierException) ex;

            try {
                sendAlertMail("Register", dso, DOI.SCHEME + doiRow.getDoi(),
                        doiIdentifierException.codeToString(doiIdentifierException.getCode()));
            } catch (IOException ioe) {
                LOG.error("Couldn't send mail", ioe);
            }

            LOG.error("It wasn't possible to register this identifier : " + DOI.SCHEME + doiRow.getDoi()
                    + " online. Exceptions code: "
                    + doiIdentifierException.codeToString(doiIdentifierException.getCode()), ex);

            if (!quiet) {
                System.err
                        .println("It wasn't possible to register this identifier: " + DOI.SCHEME + doiRow.getDoi());
            }

        } catch (IllegalArgumentException ex) {
            LOG.error("Database table DOI contains a DOI that is not valid: " + DOI.SCHEME + doiRow.getDoi() + "!",
                    ex);

            if (!quiet) {
                System.err
                        .println("It wasn't possible to register this identifier: " + DOI.SCHEME + doiRow.getDoi());
            }

            throw new IllegalStateException("Database table DOI contains a DOI " + " that is not valid: "
                    + DOI.SCHEME + doiRow.getDoi() + "!", ex);
        } catch (SQLException ex) {
            LOG.error("Error while trying to get data from database", ex);

            if (!quiet) {
                System.err
                        .println("It wasn't possible to register this identifier: " + DOI.SCHEME + doiRow.getDoi());
            }
            throw new RuntimeException("Error while trying to get data from database", ex);
        }
    }

    public void reserve(DOI doiRow) throws SQLException {
        DSpaceObject dso = doiRow.getDSpaceObject();
        if (Constants.ITEM != dso.getType()) {
            throw new IllegalArgumentException("Currenty DSpace supports DOIs for Items only.");
        }

        try {
            provider.reserveOnline(context, dso, DOI.SCHEME + doiRow.getDoi());

            if (!quiet) {
                System.out.println(
                        "This identifier : " + DOI.SCHEME + doiRow.getDoi() + " is successfully reserved.");
            }
        } catch (IdentifierException ex) {
            if (!(ex instanceof DOIIdentifierException)) {
                LOG.error("It wasn't possible to register this identifier : " + DOI.SCHEME + doiRow.getDoi()
                        + " online. ", ex);
            }

            DOIIdentifierException doiIdentifierException = (DOIIdentifierException) ex;

            try {
                sendAlertMail("Reserve", dso, DOI.SCHEME + doiRow.getDoi(),
                        DOIIdentifierException.codeToString(doiIdentifierException.getCode()));
            } catch (IOException ioe) {
                LOG.error("Couldn't send mail", ioe);
            }

            LOG.error("It wasn't possible to reserve the identifier online. " + " Exceptions code:  "
                    + DOIIdentifierException.codeToString(doiIdentifierException.getCode()), ex);

            if (!quiet) {
                System.err
                        .println("It wasn't possible to reserve this identifier: " + DOI.SCHEME + doiRow.getDoi());
            }
        } catch (IllegalArgumentException ex) {
            LOG.error("Database table DOI contains a DOI that is not valid: " + DOI.SCHEME + doiRow.getDoi() + "!",
                    ex);

            if (!quiet) {
                System.err
                        .println("It wasn't possible to reserve this identifier: " + DOI.SCHEME + doiRow.getDoi());
            }
            throw new IllegalStateException("Database table DOI contains a DOI " + " that is not valid: "
                    + DOI.SCHEME + doiRow.getDoi() + "!", ex);
        } catch (SQLException ex) {
            LOG.error("Error while trying to get data from database", ex);

            if (!quiet) {
                System.err
                        .println("It wasn't possible to reserve this identifier: " + DOI.SCHEME + doiRow.getDoi());
            }
            throw new RuntimeException("Error while trying to get data from database", ex);

        }
    }

    public void update(DOI doiRow) {
        DSpaceObject dso = doiRow.getDSpaceObject();
        if (Constants.ITEM != dso.getType()) {
            throw new IllegalArgumentException("Currenty DSpace supports DOIs " + "for Items only.");
        }

        try {
            provider.updateMetadataOnline(context, dso, DOI.SCHEME + doiRow.getDoi());

            if (!quiet) {
                System.out.println("Successfully updated metadata of DOI " + DOI.SCHEME + doiRow.getDoi() + ".");
            }
        } catch (IdentifierException ex) {
            if (!(ex instanceof DOIIdentifierException)) {
                LOG.error("It wasn't possible to register the identifier online. ", ex);
            }

            DOIIdentifierException doiIdentifierException = (DOIIdentifierException) ex;

            try {
                sendAlertMail("Update", dso, DOI.SCHEME + doiRow.getDoi(),
                        doiIdentifierException.codeToString(doiIdentifierException.getCode()));
            } catch (IOException ioe) {
                LOG.error("Couldn't send mail", ioe);
            }

            LOG.error("It wasn't possible to update this identifier:  " + DOI.SCHEME + doiRow.getDoi()
                    + " Exceptions code:  " + doiIdentifierException.codeToString(doiIdentifierException.getCode()),
                    ex);

            if (!quiet) {
                System.err.println("It wasn't possible to update this identifier: " + DOI.SCHEME + doiRow.getDoi());
            }

        } catch (IllegalArgumentException ex) {
            LOG.error("Database table DOI contains a DOI that is not valid: " + DOI.SCHEME + doiRow.getDoi() + "!",
                    ex);

            if (!quiet) {
                System.err.println("It wasn't possible to update this identifier: " + DOI.SCHEME + doiRow.getDoi());
            }

            throw new IllegalStateException("Database table DOI contains a DOI " + " that is not valid: "
                    + DOI.SCHEME + doiRow.getDoi() + "!", ex);
        } catch (SQLException ex) {
            LOG.error("It wasn't possible to connect to the Database!", ex);
        }
    }

    public void delete(String identifier) throws SQLException {
        String doi = null;
        DOI doiRow = null;

        try {
            doi = doiService.formatIdentifier(identifier);

            // If there's no exception: we found a valid DOI. :)
            doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length()));

            if (null == doiRow) {
                throw new IllegalStateException(
                        "You specified a valid DOI," + " that is not stored in our database.");
            }
            provider.deleteOnline(context, doi);

            if (!quiet) {
                System.err.println(
                        "It was possible to delete this identifier: " + DOI.SCHEME + doiRow.getDoi() + " online.");
            }
        } catch (DOIIdentifierException ex) {
            // Identifier was not recognized as DOI.
            LOG.error("It wasn't possible to detect this identifier:  " + identifier + " Exceptions code:  "
                    + ex.codeToString(ex.getCode()), ex);

            if (!quiet) {
                System.err.println("It wasn't possible to detect this identifier: " + identifier);
            }
        } catch (IllegalArgumentException ex) {
            if (!quiet) {
                System.err.println("It wasn't possible to delete this identifier: " + DOI.SCHEME + doiRow.getDoi()
                        + " online. Take a look in log file.");
            }
        }
    }

    /**
     * Finds the TableRow in the Doi table that belongs to the specified
     * DspaceObject.
     *
     * @param identifier Either an ItemID, a DOI or a handle. If the identifier
     * contains digits only we treat it as ItemID, if not we try to find a
     * matching doi or a handle (in this order).
     * @return The TableRow or null if the Object does not have a DOI.
     * @throws SQLException if database error
     * @throws IllegalArgumentException If the identifier is null, an empty
     * String or specifies an DSpaceObject that is not an item. We currently
     * support DOIs for items only, but this may change once...
     * @throws IllegalStateException If the identifier was a valid DOI that is
     * not stored in our database or if it is a handle that is not bound to an
     * DSpaceObject.
     * @throws IdentifierException if identifier error
     */
    public DOI resolveToDOI(String identifier)
            throws SQLException, IllegalArgumentException, IllegalStateException, IdentifierException {
        if (null == identifier || identifier.isEmpty()) {
            throw new IllegalArgumentException("Identifier is null or empty.");
        }

        DOI doiRow = null;
        String doi = null;

        // detect it identifer is ItemID, handle or DOI.
        // try to detect ItemID
        if (identifier
                .matches("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[34][0-9a-fA-F]{3}-[89ab][0-9a-fA-F]{3}-[0-9a-fA-F]{12}")) {
            DSpaceObject dso = itemService.find(context, UUID.fromString(identifier));

            if (null != dso) {
                doiRow = doiService.findDOIByDSpaceObject(context, dso);

                //Check if this Item has an Identifier, mint one if it doesn't
                if (null == doiRow) {
                    doi = provider.mint(context, dso);
                    doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length()));
                    return doiRow;
                }
                return doiRow;
            } else {
                throw new IllegalStateException(
                        "You specified an ItemID, " + "that is not stored in our database.");
            }
        }

        // detect handle
        DSpaceObject dso = handleService.resolveToObject(context, identifier);

        if (null != dso) {
            if (dso.getType() != Constants.ITEM) {
                throw new IllegalArgumentException("Currently DSpace supports DOIs for Items only. "
                        + "Cannot process specified handle as it does not identify an Item.");
            }

            doiRow = doiService.findDOIByDSpaceObject(context, dso);

            if (null == doiRow) {
                doi = provider.mint(context, dso);
                doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length()));
            }
            return doiRow;
        }
        // detect DOI
        try {
            doi = doiService.formatIdentifier(identifier);
            // If there's no exception: we found a valid DOI. :)
            doiRow = doiService.findByDoi(context, doi.substring(DOI.SCHEME.length()));
            if (null == doiRow) {
                throw new IllegalStateException(
                        "You specified a valid DOI," + " that is not stored in our database.");
            }
        } catch (DOIIdentifierException ex) {
            // Identifier was not recognized as DOI.
            LOG.error("It wasn't possible to detect this identifier:  " + identifier + " Exceptions code:  "
                    + ex.codeToString(ex.getCode()), ex);

            if (!quiet) {
                System.err.println("It wasn't possible to detect this identifier: " + DOI.SCHEME + doiRow.getDoi());
            }
        }

        return doiRow;
    }

    private void sendAlertMail(String action, DSpaceObject dso, String doi, String reason) throws IOException {
        String recipient = ConfigurationManager.getProperty("alert.recipient");

        try {
            if (recipient != null) {
                Email email = Email
                        .getEmail(I18nUtil.getEmailFilename(Locale.getDefault(), "doi_maintenance_error"));
                email.addRecipient(recipient);
                email.addArgument(action);
                email.addArgument(new Date());
                email.addArgument(ContentServiceFactory.getInstance().getDSpaceObjectService(dso).getTypeText(dso));
                email.addArgument(dso.getID().toString());
                email.addArgument(doi);
                email.addArgument(reason);
                email.send();

                if (!quiet) {
                    System.err.println("Email alert is sent.");
                }
            }
        } catch (Exception e) {
            LOG.warn("Unable to send email alert", e);
            if (!quiet) {
                System.err.println("Unable to send email alert.");
            }
        }
    }

    private void setQuiet() {
        this.quiet = true;
    }

}