co.kuali.rice.kew.notes.service.impl.RiceAttachmentDataToS3ConversionImpl.java Source code

Java tutorial

Introduction

Here is the source code for co.kuali.rice.kew.notes.service.impl.RiceAttachmentDataToS3ConversionImpl.java

Source

/*-
 * #%L
 * %%
 * Copyright (C) 2005 - 2019 Kuali, Inc. - All Rights Reserved
 * %%
 * You may use and modify this code under the terms of the Kuali, Inc.
 * Pre-Release License Agreement. You may not distribute it.
 * 
 * You should have received a copy of the Kuali, Inc. Pre-Release License
 * Agreement with this file. If not, please write to license@kuali.co.
 * #L%
 */

package co.kuali.rice.kew.notes.service.impl;

import co.kuali.rice.coreservice.api.attachment.RiceAttachmentDataS3Constants;
import co.kuali.rice.coreservice.api.attachment.S3FileService;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

import org.kuali.rice.core.api.criteria.PredicateFactory;
import org.kuali.rice.core.api.criteria.QueryByCriteria;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.kew.notes.Attachment;
import org.kuali.rice.krad.data.DataObjectService;
import org.kuali.rice.krad.data.PersistenceOption;
import org.kuali.rice.krad.util.KRADConstants;
import org.quartz.DisallowConcurrentExecution;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Objects;
import java.util.UUID;

@DisallowConcurrentExecution
public class RiceAttachmentDataToS3ConversionImpl implements RiceAttachmentDataToS3Conversion {

    private static final Logger LOG = LogManager.getLogger(RiceAttachmentDataToS3ConversionImpl.class);
    private static final String DELETE_FILE_FROM_FILESYSTEM = "DELETE_FILE_FROM_FILESYSTEM";

    private S3FileService riceS3FileService;
    private ParameterService parameterService;
    private DataObjectService dataObjectService;

    @Override
    public void execute() {
        LOG.info("Starting attachment conversion job for file_data to S3");

        if (!processRecords()) {
            return;
        }

        final Collection<Attachment> attachments = dataObjectService.findMatching(Attachment.class,
                QueryByCriteria.Builder.fromPredicates(PredicateFactory.isNotNull("fileLoc"))).getResults();
        attachments.forEach(attachment -> {
            try {
                final File file = new File(attachment.getFileLoc());
                if (file.isFile() && file.exists()) {
                    final byte[] fsBytes = FileUtils.readFileToByteArray(file);
                    String fileDataId = attachment.getFileDataId();
                    final Object s3File;
                    if (StringUtils.isBlank(fileDataId)) {
                        fileDataId = UUID.randomUUID().toString();
                        s3File = null;
                    } else {
                        s3File = riceS3FileService.retrieveFile(fileDataId);
                    }

                    final byte[] s3Bytes;
                    if (s3File == null) {
                        final Class<?> s3FileClass = Class.forName(RiceAttachmentDataS3Constants.S3_FILE_CLASS);
                        final Object newS3File = s3FileClass.newInstance();

                        final Method setId = s3FileClass.getMethod(RiceAttachmentDataS3Constants.SET_ID_METHOD,
                                String.class);
                        setId.invoke(newS3File, fileDataId);

                        final Method setFileContents = s3FileClass.getMethod(
                                RiceAttachmentDataS3Constants.SET_FILE_CONTENTS_METHOD, InputStream.class);
                        try (InputStream stream = new BufferedInputStream(new ByteArrayInputStream(fsBytes))) {
                            setFileContents.invoke(newS3File, stream);
                            riceS3FileService.createFile(newS3File);
                        }

                        s3Bytes = getBytesFromS3File(riceS3FileService.retrieveFile(fileDataId));
                    } else {
                        if (LOG.isDebugEnabled()) {
                            final Method getFileMetaData = s3File.getClass()
                                    .getMethod(RiceAttachmentDataS3Constants.GET_FILE_META_DATA_METHOD);
                            LOG.debug("data found in S3, existing id: " + fileDataId + " attachment id "
                                    + attachment.getAttachmentId() + " metadata: "
                                    + getFileMetaData.invoke(s3File));
                        }
                        s3Bytes = getBytesFromS3File(s3File);
                    }

                    if (s3Bytes != null && fsBytes != null) {
                        final String s3MD5 = DigestUtils.md5Hex(s3Bytes);
                        final String dbMD5 = DigestUtils.md5Hex(fsBytes);
                        if (!Objects.equals(s3MD5, dbMD5)) {
                            LOG.error("S3 data MD5: " + s3MD5 + " does not equal DB data MD5: " + dbMD5
                                    + " for id: " + fileDataId + " attachment id " + attachment.getAttachmentId());
                        } else {
                            attachment.setFileDataId(fileDataId);
                            if (isDeleteFromFileSystem()) {
                                attachment.setFileLoc(null);
                            }
                            try {
                                dataObjectService.save(attachment, PersistenceOption.FLUSH);
                            } finally {
                                if (isDeleteFromFileSystem()) {
                                    file.delete();
                                }
                            }
                        }
                    }
                }
            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | IOException
                    | ClassNotFoundException | InstantiationException e) {
                throw new RuntimeException(e);
            }
        });
        LOG.info("Finishing attachment conversion job for file_data to S3");
    }

    protected byte[] getBytesFromS3File(Object s3File)
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, IOException {
        byte[] s3Bytes;
        final Method getFileContents = s3File.getClass()
                .getMethod(RiceAttachmentDataS3Constants.GET_FILE_CONTENTS_METHOD);
        final InputStream fileContents = (InputStream) getFileContents.invoke(s3File);
        s3Bytes = IOUtils.toByteArray(fileContents);
        return s3Bytes;
    }

    protected boolean processRecords() {
        final boolean s3IntegrationEnabled = isS3IntegrationEnabled();
        if (!s3IntegrationEnabled) {
            LOG.info("S3 integration is not enabled.  Records will not be processed");
        }

        final boolean s3DualSaveEnabled = isS3DualSaveEnabled();
        if (s3DualSaveEnabled) {
            LOG.info("S3 dual save is enabled.  Records will not be processed");
        }
        return s3IntegrationEnabled && !s3DualSaveEnabled;
    }

    protected boolean isS3IntegrationEnabled() {
        if (parameterService.parameterExists(KRADConstants.KUALI_RICE_SYSTEM_NAMESPACE,
                KRADConstants.DetailTypes.ALL_DETAIL_TYPE, RiceAttachmentDataS3Constants.S3_INTEGRATION_ENABLED)) {
            return parameterService.getParameterValueAsBoolean(KRADConstants.KUALI_RICE_SYSTEM_NAMESPACE,
                    KRADConstants.DetailTypes.ALL_DETAIL_TYPE,
                    RiceAttachmentDataS3Constants.S3_INTEGRATION_ENABLED);
        } else {
            return false;
        }
    }

    protected boolean isS3DualSaveEnabled() {
        return parameterService.getParameterValueAsBoolean(KRADConstants.KUALI_RICE_SYSTEM_NAMESPACE,
                KRADConstants.DetailTypes.ALL_DETAIL_TYPE, RiceAttachmentDataS3Constants.S3_DUAL_SAVE_ENABLED);
    }

    protected boolean isDeleteFromFileSystem() {
        return parameterService.getParameterValueAsBoolean(KRADConstants.KUALI_RICE_SYSTEM_NAMESPACE,
                KRADConstants.DetailTypes.ALL_DETAIL_TYPE, DELETE_FILE_FROM_FILESYSTEM);
    }

    public S3FileService getRiceS3FileService() {
        return riceS3FileService;
    }

    public void setRiceS3FileService(S3FileService riceS3FileService) {
        this.riceS3FileService = riceS3FileService;
    }

    public ParameterService getParameterService() {
        return parameterService;
    }

    public void setParameterService(ParameterService parameterService) {
        this.parameterService = parameterService;
    }

    public DataObjectService getDataObjectService() {
        return dataObjectService;
    }

    public void setDataObjectService(DataObjectService dataObjectService) {
        this.dataObjectService = dataObjectService;
    }
}