cz.cas.lib.proarc.webapp.server.rest.ExportResource.java Source code

Java tutorial

Introduction

Here is the source code for cz.cas.lib.proarc.webapp.server.rest.ExportResource.java

Source

/*
 * Copyright (C) 2012 Jan Pokorsky
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */
package cz.cas.lib.proarc.webapp.server.rest;

import cz.cas.lib.proarc.common.config.AppConfiguration;
import cz.cas.lib.proarc.common.config.AppConfigurationException;
import cz.cas.lib.proarc.common.config.AppConfigurationFactory;
import cz.cas.lib.proarc.common.export.DataStreamExport;
import cz.cas.lib.proarc.common.export.DesaExport;
import cz.cas.lib.proarc.common.export.DesaExport.Result;
import cz.cas.lib.proarc.common.export.ExportException;
import cz.cas.lib.proarc.common.export.ExportResultLog;
import cz.cas.lib.proarc.common.export.ExportResultLog.ResultError;
import cz.cas.lib.proarc.common.export.Kramerius4Export;
import cz.cas.lib.proarc.common.export.NdkExport;
import cz.cas.lib.proarc.common.export.archive.ArchiveProducer;
import cz.cas.lib.proarc.common.export.cejsh.CejshConfig;
import cz.cas.lib.proarc.common.export.cejsh.CejshExport;
import cz.cas.lib.proarc.common.export.cejsh.CejshStatusHandler;
import cz.cas.lib.proarc.common.export.crossref.CrossrefExport;
import cz.cas.lib.proarc.common.export.mets.MetsExportException.MetsExportExceptionElement;
import cz.cas.lib.proarc.common.fedora.RemoteStorage;
import cz.cas.lib.proarc.common.object.DigitalObjectManager;
import cz.cas.lib.proarc.common.object.model.MetaModelRepository;
import cz.cas.lib.proarc.common.user.UserProfile;
import cz.cas.lib.proarc.webapp.shared.rest.ExportResourceApi;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.SecurityContext;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.commons.io.FileUtils;
import org.glassfish.jersey.server.CloseableService;

/**
 * REST resource to export data from the system.
 *
 * @author Jan Pokorsky
 */
@Path(ExportResourceApi.PATH)
public class ExportResource {

    private final AppConfiguration appConfig;
    private final UserProfile user;
    private final SessionContext session;

    public ExportResource(@Context SecurityContext securityCtx, @Context HttpServletRequest httpRequest)
            throws AppConfigurationException {

        this.appConfig = AppConfigurationFactory.getInstance().defaultInstance();
        session = SessionContext.from(httpRequest);
        user = session.getUser();
    }

    @POST
    @Path(ExportResourceApi.DATASTREAM_PATH)
    @Produces({ MediaType.APPLICATION_JSON })
    public SmartGwtResponse<ExportResult> datastream(
            @FormParam(ExportResourceApi.DATASTREAM_PID_PARAM) List<String> pids,
            @FormParam(ExportResourceApi.DATASTREAM_DSID_PARAM) List<String> dsIds,
            @FormParam(ExportResourceApi.DATASTREAM_HIERARCHY_PARAM) @DefaultValue("true") boolean hierarchy)
            throws IOException, ExportException {

        if (pids.isEmpty()) {
            throw RestException.plainText(Status.BAD_REQUEST, "Missing " + ExportResourceApi.DATASTREAM_PID_PARAM);
        }
        if (dsIds.isEmpty()) {
            throw RestException.plainText(Status.BAD_REQUEST, "Missing " + ExportResourceApi.DATASTREAM_DSID_PARAM);
        }
        DataStreamExport export = new DataStreamExport(RemoteStorage.getInstance(appConfig));
        URI exportUri = user.getExportFolder();
        File exportFolder = new File(exportUri);
        File target = export.export(exportFolder, hierarchy, pids, dsIds);
        URI targetPath = user.getUserHomeUri().relativize(target.toURI());
        return new SmartGwtResponse<ExportResult>(new ExportResult(targetPath));
    }

    @POST
    @Path(ExportResourceApi.KRAMERIUS4_PATH)
    @Produces({ MediaType.APPLICATION_JSON })
    public SmartGwtResponse<ExportResult> kramerius4(
            @FormParam(ExportResourceApi.KRAMERIUS4_PID_PARAM) List<String> pids,
            @FormParam(ExportResourceApi.KRAMERIUS4_HIERARCHY_PARAM) @DefaultValue("true") boolean hierarchy)
            throws IOException {

        if (pids.isEmpty()) {
            throw RestException.plainText(Status.BAD_REQUEST, "Missing " + ExportResourceApi.KRAMERIUS4_PID_PARAM);
        }
        Kramerius4Export export = new Kramerius4Export(RemoteStorage.getInstance(appConfig),
                appConfig.getKramerius4Export());
        URI exportUri = user.getExportFolder();
        File exportFolder = new File(exportUri);
        File target = export.export(exportFolder, hierarchy, session.asFedoraLog(),
                pids.toArray(new String[pids.size()]));
        URI targetPath = user.getUserHomeUri().relativize(target.toURI());
        return new SmartGwtResponse<ExportResult>(new ExportResult(targetPath));
    }

    /**
     * Starts a new export to DESA repository.
     *
     * @param pids PIDs to export
     * @param hierarchy export also children hierarchy of requested PIDs. Default is {@code false}.
     * @param forDownload export to file system for later client download. If {@code true} dryRun is ignored.
     *              Default is {@code false}.
     * @param dryRun use to build packages without sending to the repository. Default is {@code false}.
     * @return the list of results for requested PIDs
     * @throws IOException unexpected failure
     * @throws ExportException unexpected failure
     */
    @POST
    @Path(ExportResourceApi.DESA_PATH)
    @Produces({ MediaType.APPLICATION_JSON })
    public SmartGwtResponse<ExportResult> newDesaExport(
            @FormParam(ExportResourceApi.DESA_PID_PARAM) List<String> pids,
            @FormParam(ExportResourceApi.DESA_HIERARCHY_PARAM) @DefaultValue("false") boolean hierarchy,
            @FormParam(ExportResourceApi.DESA_FORDOWNLOAD_PARAM) @DefaultValue("false") boolean forDownload,
            @FormParam(ExportResourceApi.DESA_DRYRUN_PARAM) @DefaultValue("false") boolean dryRun)
            throws IOException, ExportException {

        if (pids.isEmpty()) {
            throw RestException.plainText(Status.BAD_REQUEST, "Missing " + ExportResourceApi.DESA_PID_PARAM);
        }
        DesaExport export = new DesaExport(RemoteStorage.getInstance(appConfig), appConfig.getDesaServices(),
                MetaModelRepository.getInstance());
        URI exportUri = user.getExportFolder();
        File exportFolder = new File(exportUri);
        List<ExportResult> result = new ArrayList<ExportResult>(pids.size());
        if (forDownload) {
            Result r = export.exportDownload(exportFolder, pids.get(0));
            result.add(r.getValidationError() != null ? new ExportResult(r.getValidationError().getExceptions())
                    : new ExportResult(r.getDownloadToken()));
        } else {
            if (dryRun) {
                for (String pid : pids) {
                    List<MetsExportExceptionElement> errors = export.validate(exportFolder, pid, hierarchy);
                    result.add(new ExportResult(errors));
                }
            } else {
                for (String pid : pids) {
                    Result r = export.export(exportFolder, pid, null, false, hierarchy, false,
                            session.asFedoraLog(), user);
                    if (r.getValidationError() != null) {
                        result.add(new ExportResult(r.getValidationError().getExceptions()));
                    } else {
                        // XXX not used for now
                        result.add(new ExportResult((Integer) null, "done"));
                    }
                }
            }
        }
        return new SmartGwtResponse<ExportResult>(result);
    }

    /**
     * Gets the exported package built by {@link #newDesaExport() } with {@code forDownload=true}.
     * The package data are removed after completion of the response.
     *
     * @param token token to identify the prepared package
     * @return the package contents in ZIP format
     */
    @GET
    @Path(ExportResourceApi.DESA_PATH)
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response getDesaExport(@QueryParam(ExportResourceApi.RESULT_TOKEN) String token,
            @Context CloseableService finalizer) {

        URI exportUri = user.getExportFolder();
        File exportFolder = new File(exportUri);
        final File file = DesaExport.findExportedPackage(exportFolder, token);
        if (file == null) {
            return Response.status(Status.NOT_FOUND).type(MediaType.TEXT_PLAIN_TYPE)
                    .entity("The contents not found!").build();
        }
        finalizer.add(new Closeable() {

            @Override
            public void close() throws IOException {
                FileUtils.deleteQuietly(file.getParentFile());
            }
        });
        return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
                .header("Content-Disposition", "attachment; filename=\"" + file.getName() + '"').build();
    }

    @POST
    @Path(ExportResourceApi.NDK_PATH)
    @Produces({ MediaType.APPLICATION_JSON })
    public SmartGwtResponse<ExportResult> newNdkExport(@FormParam(ExportResourceApi.NDK_PID_PARAM) List<String> pids
    //            @FormParam(ExportResourceApi.DESA_HIERARCHY_PARAM) @DefaultValue("false") boolean hierarchy,
    //            @FormParam(ExportResourceApi.DESA_FORDOWNLOAD_PARAM) @DefaultValue("false") boolean forDownload,
    //            @FormParam(ExportResourceApi.DESA_DRYRUN_PARAM) @DefaultValue("false") boolean dryRun
    ) throws ExportException {

        if (pids.isEmpty()) {
            throw RestException.plainText(Status.BAD_REQUEST, "Missing " + ExportResourceApi.DESA_PID_PARAM);
        }
        URI exportUri = user.getExportFolder();
        File exportFolder = new File(exportUri);
        List<ExportResult> result = new ArrayList<ExportResult>(pids.size());
        NdkExport export = new NdkExport(RemoteStorage.getInstance());
        List<NdkExport.Result> ndkResults = export.export(exportFolder, pids, true, true, session.asFedoraLog());
        for (NdkExport.Result r : ndkResults) {
            if (r.getValidationError() != null) {
                result.add(new ExportResult(r.getValidationError().getExceptions()));
            } else {
                // XXX not used for now
                result.add(new ExportResult((Integer) null, "done"));
            }
        }
        return new SmartGwtResponse<ExportResult>(result);
    }

    /**
     * Starts a new CEJSH export.
     * @param pids PIDs to export
     * @return the export result
     */
    @POST
    @Path(ExportResourceApi.CEJSH_PATH)
    @Produces({ MediaType.APPLICATION_JSON })
    public SmartGwtResponse<ExportResult> newCejshExport(
            @FormParam(ExportResourceApi.CEJSH_PID_PARAM) List<String> pids) {

        if (pids.isEmpty()) {
            throw RestException.plainText(Status.BAD_REQUEST, "Missing " + ExportResourceApi.CEJSH_PID_PARAM);
        }
        URI exportUri = user.getExportFolder();
        File exportFolder = new File(exportUri);
        CejshConfig cejshConfig = CejshConfig.from(appConfig.getAuthenticators());
        CejshExport export = new CejshExport(DigitalObjectManager.getDefault(), RemoteStorage.getInstance(),
                cejshConfig);
        CejshStatusHandler status = export.export(exportFolder, pids);
        File targetFolder = status.getTargetFolder();
        ExportResult result = new ExportResult();
        if (targetFolder != null) {
            result.setTarget(user.getUserHomeUri().relativize(targetFolder.toURI()).toASCIIString());
        }
        if (!status.isOk()) {
            result.setErrors(new ArrayList<ExportError>());
            for (ExportResultLog.ExportResult logResult : status.getReslog().getExports()) {
                for (ResultError error : logResult.getError()) {
                    result.getErrors()
                            .add(new ExportError(error.getPid(), error.getMessage(), false, error.getDetails()));
                }
            }
        }
        return new SmartGwtResponse<ExportResult>(result);
    }

    /**
     * Starts a new Crossref export.
     * @param pids PIDs to export
     * @return the export result
     */
    @POST
    @Path(ExportResourceApi.CROSSREF_PATH)
    @Produces({ MediaType.APPLICATION_JSON })
    public SmartGwtResponse<ExportResult> newCrossrefExport(
            @FormParam(ExportResourceApi.CROSSREF_PID_PARAM) List<String> pids) {

        if (pids.isEmpty()) {
            throw RestException.plainText(Status.BAD_REQUEST, "Missing " + ExportResourceApi.CROSSREF_PID_PARAM);
        }
        URI exportUri = user.getExportFolder();
        File exportFolder = new File(exportUri);
        //        CejshConfig cejshConfig = CejshConfig.from(appConfig.getAuthenticators());
        CrossrefExport export = new CrossrefExport(DigitalObjectManager.getDefault(), RemoteStorage.getInstance());
        CejshStatusHandler status = new CejshStatusHandler();
        export.export(exportFolder, pids, status);
        File targetFolder = status.getTargetFolder();
        ExportResult result = new ExportResult();
        if (targetFolder != null) {
            result.setTarget(user.getUserHomeUri().relativize(targetFolder.toURI()).toASCIIString());
        }
        if (!status.isOk()) {
            result.setErrors(new ArrayList<ExportError>());
            for (ExportResultLog.ExportResult logResult : status.getReslog().getExports()) {
                for (ResultError error : logResult.getError()) {
                    result.getErrors()
                            .add(new ExportError(error.getPid(), error.getMessage(), false, error.getDetails()));
                }
            }
        }
        return new SmartGwtResponse<ExportResult>(result);
    }

    /**
     * Starts new archiving.
     * @param pids PIDs to export
     * @return the export result
     */
    @POST
    @Path(ExportResourceApi.ARCHIVE_PATH)
    @Produces({ MediaType.APPLICATION_JSON })
    public SmartGwtResponse<ExportResult> newArchive(
            @FormParam(ExportResourceApi.ARCHIVE_PID_PARAM) List<String> pids) {

        if (pids.isEmpty()) {
            throw RestException.plainText(Status.BAD_REQUEST, "Missing " + ExportResourceApi.ARCHIVE_PID_PARAM);
        }
        URI exportUri = user.getExportFolder();
        File exportFolder = new File(exportUri);
        ExportResult result = new ExportResult();
        ArchiveProducer export = new ArchiveProducer();
        try {
            File targetFolder = export.archive(pids, exportFolder);
            if (targetFolder != null) {
                result.setTarget(user.getUserHomeUri().relativize(targetFolder.toURI()).toASCIIString());
            }
        } catch (Exception ex) {
            Logger.getLogger(ExportResource.class.getName()).log(Level.SEVERE, null, ex);
        }
        ExportResultLog reslog = export.getResultLog();
        result.setErrors(new ArrayList<ExportError>());
        for (ExportResultLog.ExportResult logResult : reslog.getExports()) {
            for (ResultError error : logResult.getError()) {
                result.getErrors()
                        .add(new ExportError(error.getPid(), error.getMessage(), false, error.getDetails()));
            }
        }
        return new SmartGwtResponse<ExportResult>(result);
    }

    /**
     * The export result.
     */
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class ExportResult {

        @XmlElement(name = ExportResourceApi.RESULT_ID)
        private Integer exportId;

        @XmlElement(name = ExportResourceApi.RESULT_TOKEN)
        private String token;

        /**
         * The target folder path.
         */
        @XmlElement(name = ExportResourceApi.RESULT_TARGET)
        private String target;

        @XmlElement(name = ExportResourceApi.RESULT_ERRORS)
        private List<ExportError> errors;

        public ExportResult() {
        }

        public ExportResult(URI targetPath) {
            this.target = targetPath.toASCIIString();
        }

        public ExportResult(String token) {
            this.token = token;
        }

        public ExportResult(Integer exportId, String target) {
            this.exportId = exportId;
            this.target = target;
        }

        public ExportResult(List<MetsExportExceptionElement> validations) {
            if (validations != null) {
                errors = new ArrayList<ExportError>();
                for (MetsExportExceptionElement me : validations) {
                    errors.add(new ExportError(me));
                }
            }
        }

        public Integer getExportId() {
            return exportId;
        }

        public String getTarget() {
            return target;
        }

        public List<ExportError> getErrors() {
            return errors;
        }

        public void setExportId(Integer exportId) {
            this.exportId = exportId;
        }

        public void setTarget(String target) {
            this.target = target;
        }

        public void setErrors(List<ExportError> errors) {
            this.errors = errors;
        }

        public String getToken() {
            return token;
        }

        public void setToken(String token) {
            this.token = token;
        }

    }

    /**
     * The export error.
     */
    @XmlRootElement(name = ExportResourceApi.RESULT_ERROR)
    public static class ExportError {

        @XmlElement(name = ExportResourceApi.RESULT_ERROR_PID)
        private String pid;

        @XmlElement(name = ExportResourceApi.RESULT_ERROR_MESSAGE)
        private String message;

        @XmlElement(name = ExportResourceApi.RESULT_ERROR_WARNING)
        private boolean warning;

        @XmlElement(name = ExportResourceApi.RESULT_ERROR_LOG)
        private String log;

        public ExportError() {
        }

        public ExportError(String pid, String message, boolean warning, String log) {
            this.pid = pid;
            this.message = message;
            this.warning = warning;
            this.log = log;
        }

        public ExportError(MetsExportExceptionElement me) {
            this.pid = me.getPid();
            this.message = me.getMessage();
            this.warning = me.isWarning();
            List<String> validations = me.getValidationErrors();
            Exception ex = me.getEx();
            if (validations != null && !validations.isEmpty()) {
                StringBuilder sb = new StringBuilder();
                for (String validation : validations) {
                    if (message == null) {
                        message = validation;
                    }
                    sb.append(validation).append('\n');
                }
                this.log = sb.toString();
            } else if (ex != null) {
                StringWriter sw = new StringWriter();
                PrintWriter pw = new PrintWriter(sw);
                ex.printStackTrace(pw);
                pw.close();
                this.log = sw.toString();
            }
        }

    }

}