Java tutorial
/*- * #%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; } }