co.kuali.rice.krad.service.impl.S3AttachmentServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for co.kuali.rice.krad.service.impl.S3AttachmentServiceImpl.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.krad.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.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.mo.common.GloballyUnique;
import org.kuali.rice.coreservice.framework.parameter.ParameterService;
import org.kuali.rice.krad.bo.Attachment;
import org.kuali.rice.krad.bo.Note;
import org.kuali.rice.krad.service.impl.AttachmentServiceImpl;
import org.kuali.rice.krad.util.KRADConstants;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;

public class S3AttachmentServiceImpl extends AttachmentServiceImpl {

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

    private S3FileService riceS3FileService;
    private ParameterService parameterService;

    @Override
    public Attachment createAttachment(GloballyUnique parent, String uploadedFileName, String mimeType,
            int fileSize, InputStream fileContents, String attachmentType) throws IOException {
        if (!isS3IntegrationEnabled()) {
            return super.createAttachment(parent, uploadedFileName, mimeType, fileSize, fileContents,
                    attachmentType);
        }

        if (LOG.isDebugEnabled()) {
            LOG.debug("starting to create attachment for document: " + parent.getObjectId());
        }
        if (parent == null) {
            throw new IllegalArgumentException("invalid (null or uninitialized) document");
        }
        if (StringUtils.isBlank(uploadedFileName)) {
            throw new IllegalArgumentException("invalid (blank) fileName");
        }
        if (StringUtils.isBlank(mimeType)) {
            throw new IllegalArgumentException("invalid (blank) mimeType");
        }
        if (fileSize <= 0) {
            throw new IllegalArgumentException("invalid (non-positive) fileSize");
        }
        if (fileContents == null) {
            throw new IllegalArgumentException("invalid (null) inputStream");
        }

        final byte[] bytes = IOUtils.toByteArray(fileContents);
        final String uniqueFileNameGuid;
        try {
            final Class<?> s3FileClass = Class.forName(RiceAttachmentDataS3Constants.S3_FILE_CLASS);
            final Object s3File = s3FileClass.newInstance();

            final Method setFileContents = s3FileClass
                    .getMethod(RiceAttachmentDataS3Constants.SET_FILE_CONTENTS_METHOD, InputStream.class);
            setFileContents.invoke(s3File, new BufferedInputStream(new ByteArrayInputStream(bytes)));

            uniqueFileNameGuid = riceS3FileService.createFile(s3File);
        } catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException | InstantiationException
                | InvocationTargetException e) {
            throw new RuntimeException(e);
        }

        if (isS3DualSaveEnabled()) {
            String fullPathUniqueFileName = getDocumentDirectory(parent.getObjectId()) + File.separator
                    + uniqueFileNameGuid;
            writeInputStreamToFileStorage(new BufferedInputStream(new ByteArrayInputStream(bytes)),
                    fullPathUniqueFileName);
        }

        // create DocumentAttachment
        final Attachment attachment = new Attachment();
        attachment.setAttachmentIdentifier(uniqueFileNameGuid);
        attachment.setAttachmentFileName(uploadedFileName);
        attachment.setAttachmentFileSize((long) fileSize);
        attachment.setAttachmentMimeTypeCode(mimeType);
        attachment.setAttachmentTypeCode(attachmentType);

        if (LOG.isDebugEnabled()) {
            LOG.debug("finished creating attachment for document: " + parent.getObjectId());
        }

        return attachment;
    }

    @Override
    public InputStream retrieveAttachmentContents(Attachment attachment) throws IOException {
        if (!isS3IntegrationEnabled()) {
            return super.retrieveAttachmentContents(attachment);
        }

        try {
            final Object s3File = riceS3FileService.retrieveFile(attachment.getAttachmentIdentifier());
            byte[] s3Bytes = null;
            byte[] fsBytes = null;
            if (s3File != null) {
                if (LOG.isDebugEnabled()) {
                    final Method getFileMetaData = s3File.getClass()
                            .getMethod(RiceAttachmentDataS3Constants.GET_FILE_META_DATA_METHOD);
                    LOG.debug("data found in S3, existing id: " + attachment.getAttachmentIdentifier()
                            + " metadata: " + getFileMetaData.invoke(s3File));
                }

                final Method getFileContents = s3File.getClass()
                        .getMethod(RiceAttachmentDataS3Constants.GET_FILE_CONTENTS_METHOD);
                final InputStream fileContents = (InputStream) getFileContents.invoke(s3File);
                s3Bytes = IOUtils.toByteArray(fileContents);
            }

            if (s3Bytes == null || isS3DualRetrieveEnabled()) {
                String parentDirectory = "";
                if (attachment.getNote() != null && attachment.getNote().getRemoteObjectIdentifier() != null) {
                    parentDirectory = attachment.getNote().getRemoteObjectIdentifier();
                }

                final Path path = Paths.get(getDocumentDirectory(parentDirectory),
                        attachment.getAttachmentIdentifier());
                try {
                    fsBytes = Files.readAllBytes(path);
                } catch (NoSuchFileException e) {
                    LOG.info("file not found at path " + path);
                }
            }

            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 FS data MD5: " + dbMD5 + " for id: "
                            + attachment.getAttachmentIdentifier());
                }
            }

            return new ByteArrayInputStream(s3Bytes != null ? s3Bytes : fsBytes);
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void deleteAttachmentContents(Attachment attachment) {
        if (!isS3IntegrationEnabled()) {
            super.deleteAttachmentContents(attachment);
            return;
        }

        if (attachment.getNote() == null) {
            throw new RuntimeException("Attachment.note must be set in order to delete the attachment");
        }

        riceS3FileService.deleteFile(attachment.getAttachmentIdentifier());

        if (isS3DualSaveEnabled()) {
            final String fullPathUniqueFileName = getDocumentDirectory(
                    attachment.getNote().getRemoteObjectIdentifier()) + File.separator
                    + attachment.getAttachmentIdentifier();
            final File attachmentFile = new File(fullPathUniqueFileName);
            if (attachmentFile.exists()) {
                attachmentFile.delete();
            }
        }
    }

    @Override
    public void moveAttachmentWherePending(Note note) {
        if (!isS3IntegrationEnabled() || isS3DualSaveEnabled()) {
            super.moveAttachmentWherePending(note);
            return;
        }

        if (note == null) {
            throw new IllegalArgumentException("Note must be non-null");
        }

        if (StringUtils.isBlank(note.getObjectId())) {
            throw new IllegalArgumentException("Note does not have a valid object id, object id was null or empty");
        }
    }

    @Override
    public void deletePendingAttachmentsModifiedBefore(long modificationTime) {
        if (!isS3IntegrationEnabled() || isS3DualSaveEnabled()) {
            super.deletePendingAttachmentsModifiedBefore(modificationTime);
            return;
        }
    }

    @Override
    public Attachment getAttachmentByNoteId(Long noteId) {
        return super.getAttachmentByNoteId(noteId);
    }

    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 isS3DualRetrieveEnabled() {
        return parameterService.getParameterValueAsBoolean(KRADConstants.KUALI_RICE_SYSTEM_NAMESPACE,
                KRADConstants.DetailTypes.ALL_DETAIL_TYPE, RiceAttachmentDataS3Constants.S3_DUAL_RETRIEVE_ENABLED);
    }

    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;
    }
}