com.disney.opa.util.AttachmentUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.disney.opa.util.AttachmentUtils.java

Source

package com.disney.opa.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.activation.MimetypesFileTypeMap;
import javax.validation.ValidationException;
import javax.ws.rs.container.ContainerRequestContext;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.glassfish.jersey.media.multipart.FormDataBodyPart;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.disney.opa.bean.UserInfo;
import com.disney.opa.dao.SearchEngineDao;
import com.disney.opa.dom.image.OPAImage;
import com.disney.opa.dom.module.Module;
import com.disney.opa.dom.product.Attachment;
import com.disney.opa.dom.product.Product;
import com.disney.opa.dom.product.ProductState;
import com.disney.opa.dom.user.UserSelectionTypes;
import com.disney.opa.helper.user.UserPermission;
import com.disney.opa.json.request.AddAttachmentRequest;
import com.disney.opa.json.response.BaseJsonResponse;
import com.disney.opa.search.PASearchResultSet;
import com.disney.opa.service.ImageService;
import com.disney.opa.service.ModuleService;
import com.disney.opa.service.UtilityService;
import com.disney.opa.template.ModuleTypes;
import com.disney.opa.template.PageTypes;

/**
 * This class is an utility class for attachment related functionality.
 *
 */
@Component
public class AttachmentUtils {

    @Autowired
    private ImageService imageService;

    @Autowired
    private UtilityService utilityService;

    @Autowired
    private SearchEngineDao searchEngineDao;

    @Autowired
    private ModuleService moduleService;

    private static final Logger log = Logger.getLogger(AttachmentUtils.class);

    private static final int PRODUCT_DIR_DIVISOR = 10000;

    private static MimetypesFileTypeMap mimetypesFileTypeMap = null;

    /**
     * This method is to get the root path of attachments from OPAProperties.
     * 
     * @return images directory
     * @throws Exception
     */
    public String getRootAttachmentPath() throws Exception {
        return utilityService.getOPAPropertyValue("imagesDir");
    }

    /**
     * Based on product id get the relative path of images directory.
     * 
     * @param productId
     * @return images directory relative path
     */
    public String getRelativeFilePath(int productId) {
        int productDirNumber = productId / PRODUCT_DIR_DIVISOR;
        return File.separator + productDirNumber + File.separator + productId + "_images";
    }

    /**
     * This method is to get relative path of original files.
     * 
     * @param productId
     * @return original files relative path
     */
    public String getRelativeOriginalFilePath(int productId) {
        int productDirNumber = productId / PRODUCT_DIR_DIVISOR;
        return File.separator + productDirNumber + File.separator + productId + "_images" + File.separator
                + "original";
    }

    /**
     * Get the attachments path using product id to store original files.
     * 
     * @param productId
     * @return original attachments path
     * @throws Exception
     */
    public String getOriginalAttachmentsPath(int productId) throws Exception {
        String pathname = getRootAttachmentPath() + getRelativeFilePath(productId) + File.separator + "original";
        File dir = new File(pathname);
        if (!dir.exists() && !dir.mkdirs()) {
            throw new IOException("Could not create images directory: " + pathname);
        }
        return pathname;
    }

    /**
     * Based on file extension get the mime type.
     * 
     * @param filename
     * @return mime type
     */
    public static String getMimeType(String filename) {
        if (mimetypesFileTypeMap == null) {
            mimetypesFileTypeMap = new MimetypesFileTypeMap();
            mimetypesFileTypeMap.addMimeTypes("image/bmp            bmp");
            mimetypesFileTypeMap.addMimeTypes("image/gif            gif");
            mimetypesFileTypeMap.addMimeTypes("image/jpeg            jpg jpe jpeg");
            mimetypesFileTypeMap.addMimeTypes("application/pdf         pdf");
            mimetypesFileTypeMap.addMimeTypes("application/postscript   ps eps ai");
            mimetypesFileTypeMap.addMimeTypes("image/targa            tar targa");
            mimetypesFileTypeMap.addMimeTypes("image/tiff            tif tiff");
            mimetypesFileTypeMap.addMimeTypes("image/png            png");
            mimetypesFileTypeMap.addMimeTypes("application/photoshop   psd pdd");
            mimetypesFileTypeMap.addMimeTypes("application/octet-stream   img");
        }
        return mimetypesFileTypeMap.getContentType(filename);
    }

    /**
     * This method is to get file extension using file name.
     * 
     * @param filename
     * @return the file extension
     */
    public String getFileExtension(String filename) {
        int index = filename.lastIndexOf(".");
        if (index >= 0) {
            return filename.substring(index + 1);
        }
        return null;
    }

    /**
     * This method is to get relative thumb nails path using product id.
     * 
     * @param productId
     * @return relative thumb nails path
     */
    public String getRelativeThumbnailsPath(int productId) {
        return getRelativeFilePath(productId) + File.separator + "thumbnails";
    }

    /**
     * Create thumb nail file name using original file name.
     * 
     * @param fileName
     * @return thumb nail file name
     */
    public String getThumbnailFileName(String fileName) {
        String thumbnailFileName = new File(fileName).getName();
        int index = thumbnailFileName.lastIndexOf(".");
        if (index < 0) {
            return thumbnailFileName + ".jpg";
        }
        return thumbnailFileName.substring(0, index) + ".jpg";
    }

    /**
     * This method is to create an attachment object and verifies the file existence on disk.
     * 
     * @param fileName
     * @param fileLabel
     * @param productId
     * @param productStateID
     * @param userID
     * @return an attachment
     */
    public Attachment getAttachment(String fileName, String fileLabel, int productId, int productStateID,
            int userID) {
        Attachment attachment = new Attachment();
        try {
            attachment.setProductID(productId);
            attachment.setProductStateID(productStateID);
            attachment.setName(fileLabel);
            attachment.setFilename(fileName);
            attachment.setUserID(userID);
            attachment.setMimeType(AttachmentUtils.getMimeType(fileName));
            String imageFile = getRelativeOriginalFilePath(productId) + File.separator + fileName;
            attachment.setFilePath(imageFile);
            attachment.setThumbnailFilePath(null);
            Path path = Paths.get(getRootAttachmentPath() + imageFile);
            if (Files.exists(path)) {
                attachment.setFileSize(Files.size(path));
            }

        } catch (Exception e) {
            log.error("Error in getAttachment, fileName: " + fileName + ", fileLabel: " + fileLabel
                    + ", productId: " + productId + ", userID: " + userID, e);
        }
        return attachment;
    }

    /**
     * This method handles the user save attachment request.
     * 
     * @param addRequest
     * @param productStateID
     * @param fileNames
     * @param fileLabels
     * @param errors
     * @return list of attachments supplied by user
     * @throws Exception
     */
    public List<Attachment> processRequest(AddAttachmentRequest addRequest, int productStateID,
            List<String> fileNames, List<String> fileLabels, List<String> errors) throws Exception {
        List<Attachment> attachments = new ArrayList<Attachment>();
        for (AddAttachmentRequest.File file : addRequest.getFiles()) {
            String fileExt = getFileExtension(file.getImageFileName());
            Attachment attachment = getAttachment(file.getImageFileName(), file.getFileLabel(),
                    addRequest.getProductId(), productStateID, addRequest.getLogonUserId());
            if (attachment.getFileSize() == 0L) {
                errors.add("File not found, file name: " + file.getImageFileName() + ", title: "
                        + file.getFileLabel());
            } else if ("zip".equalsIgnoreCase(fileExt)) {
                attachments.addAll(processZipFile(attachment, fileNames, fileLabels, errors));
                attachment
                        .setName(createUniqueFileLabel(attachment.getFilename(), attachment.getName(), fileLabels));
                attachment.setName(attachment.getName() + ".PENDING");
                attachments.add(attachment);
            } else {
                attachment
                        .setName(createUniqueFileLabel(attachment.getFilename(), attachment.getName(), fileLabels));
                attachments.add(attachment);
            }
        }
        return attachments;
    }

    /**
     * This method is to extract the zip files and creates attachment objects.
     * 
     * @param attachment
     * @param fileNames
     * @param fileLabels
     * @param errors
     * @return list of attachments from the zip file
     */
    public List<Attachment> processZipFile(Attachment attachment, List<String> fileNames, List<String> fileLabels,
            List<String> errors) {
        ZipFile zipFile = null;
        List<Attachment> attachments = new ArrayList<Attachment>();
        try {
            String zipFilePath = getOriginalAttachmentsPath(attachment.getProductID()) + File.separator
                    + attachment.getFilename();
            zipFile = new ZipFile(zipFilePath);
            Enumeration<? extends ZipEntry> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = entries.nextElement();
                if (entry.isDirectory()) {
                    continue;
                }
                String fileName = entry.getName();
                File destinationFile = new File(
                        getOriginalAttachmentsPath(attachment.getProductID()) + File.separator + fileName);
                uploadFile(zipFile.getInputStream(entry), destinationFile);
                String label = createUniqueFileLabel(fileName, null, fileLabels);
                Attachment fileAttachment = getAttachment(fileName, label, attachment.getProductID(),
                        attachment.getProductStateID(), attachment.getUserID());
                if (fileAttachment.getFileSize() == 0L) {
                    errors.add("File not found, file name: " + fileName + ", in zip file: "
                            + attachment.getFilename());
                } else {
                    attachments.add(fileAttachment);
                }
            }
        } catch (Exception e) {
            errors.add(
                    "Error while processing zip: " + attachment.getFilename() + ", title: " + attachment.getName());
            log.error("Error while processing zip.", e);
        } finally {
            try {
                if (zipFile != null) {
                    zipFile.close();
                }
            } catch (IOException e) {
            }
        }
        return attachments;
    }

    /**
     * This method is to create unique file label.
     * 
     * @param fileName
     * @param fileLabel
     * @param fileLabels
     * @return unique file label
     */
    public String createUniqueFileLabel(String fileName, String fileLabel, List<String> fileLabels) {
        String newFileLabel = fileLabel;
        if (StringUtils.isEmpty(fileLabel)) {
            int index = fileName.lastIndexOf(".");
            newFileLabel = (index > 0) ? fileName.substring(0, index) : fileName;
        }
        for (int n = 1; fileLabels.contains(newFileLabel); n++) {
            newFileLabel = newFileLabel + "_" + n;
        }
        fileLabels.add(newFileLabel);
        return newFileLabel;
    }

    /**
     * This method is to create an unique isbn file name.
     * 
     * @param fileName
     * @param isbn
     * @param fileNames
     * @return unique file name.
     */
    public String createUniqueISBNFileName(String fileName, String isbn, List<String> fileNames) {
        String extension = getFileExtension(fileName);
        int index = fileName.lastIndexOf(".");
        String newFileNamePrefix = isbn + "_" + ((index > 0) ? fileName.substring(0, index) : fileName);
        String newFileName = newFileNamePrefix + "." + extension;
        for (int n = 1; fileNames.contains(newFileName); n++) {
            newFileName = newFileNamePrefix + "_" + n + "." + extension;
        }
        fileNames.add(newFileName);
        return newFileName;
    }

    /**
     * This method is to create a thumb nail to attachment.
     * 
     * @param attachment
     *            - Attachment
     */
    public void createThumbnail(Attachment attachment) {
        try {
            String extension = getFileExtension(attachment.getFilename());
            if (!LookupUtil.isThumbnailPossible(extension, attachment.getMimeType())) {
                return;
            }
            String thumbnailPath = getRelativeThumbnailsPath(attachment.getProductID());
            File parentFile = new File(attachment.getFilePath());
            String targetPassDirectory = getRelativeFilePath(attachment.getProductID());
            String targetRejectDirectory = thumbnailPath + File.separator + "reject" + File.separator + "thumb_"
                    + attachment.getFilename();
            String thumbnailImagePath = createThumbnailImageMagick(parentFile, thumbnailPath, targetPassDirectory,
                    targetRejectDirectory);
            if (StringUtils.isNotEmpty(thumbnailImagePath)) {
                attachment.setThumbnailFilePath(
                        thumbnailPath + File.separator + getThumbnailFileName(attachment.getFilePath()));
            }
        } catch (Exception e) {
            log.error("Error while creating thumnail for file: " + attachment.getFilePath(), e);
        }
    }

    /**
     * This method is to move and rename the files from original directory to images directory.
     * 
     * @param attachment
     * @param isbn
     * @param fileNames
     * @throws Exception
     */
    public void renameFile(Attachment attachment, String isbn, List<String> fileNames) throws Exception {
        String extension = getFileExtension(attachment.getFilename());
        String sourceFilePath = getRootAttachmentPath() + attachment.getFilePath();
        String destFilePath = getRootAttachmentPath() + getRelativeFilePath(attachment.getProductID())
                + File.separator + attachment.getID();
        destFilePath += (extension != null) ? "." + extension.toLowerCase() : "";
        /*
        File sourceFile = new File(sourceFilePath);
        File destFile = new File(destFilePath);
        if (!sourceFile.renameTo(destFile)) {
           log.error("File rename failed for src: " + sourceFilePath + ", dest: " + destFilePath);
           return;
        }
        */
        java.nio.file.Path FROM = Paths.get(sourceFilePath);
        java.nio.file.Path TO = Paths.get(destFilePath);
        Files.move(FROM, TO);

        attachment.setFilePath(getRelativeFilePath(attachment.getProductID()) + File.separator + TO.getFileName());
        if (StringUtils.isNotEmpty(isbn)) {
            attachment.setFilename(createUniqueISBNFileName(attachment.getFilename(), isbn, fileNames));
        }
    }

    /**
     * Create a thumbnail image directly on the NAS for a given source image. Uses the default width and height of 150x150.
     * 
     * @since OPA 6.3 (2012)
     * @param parentFile
     * @param fileType
     * @param targetPassDirectory
     * @param targetRejectDirectory
     * 
     * @return String message from conversion servlet (ImageMagick)
     * @throws Exception
     */
    public String createThumbnailImageMagick(File parentFile, String thumbnailPath, String targetPassDirectory,
            String targetRejectDirectory) throws Exception {
        String result = resizeImage(parentFile, thumbnailPath, targetPassDirectory, targetRejectDirectory, 150,
                150);
        return result;
    }

    /**
     * Creates a resized image from a given image, parentFile. If the image resizing is successful, the resized image is stored in the targetPassDirectory; otherwise, the parentFile is moved to the
     * targetRejectDirectory.
     * 
     * @param parentFile
     * @param targetPassDirectory
     * @param targetRejectDirectory
     * @return
     */
    public String resizeImage(File parentFile, String thumbnailPath, String targetPassDirectory,
            String targetRejectDirectory, int imgWidth, int imgHeight) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("createThumbnail() - start, " + "targetPassDirectory is " + targetPassDirectory);
        }
        File thumbnailImg = null;
        File originalFile = parentFile;
        try {
            OPAImage opaImage = new OPAImage(originalFile);
            opaImage.setResizeHeight(imgHeight);
            opaImage.setResizeWidth(imgWidth);
            opaImage.setResultDirectory(targetPassDirectory);
            opaImage.setThumbnailPath(thumbnailPath);
            log.info("createThumbnail Cache Dir : " + opaImage.getResultDirectory());
            boolean wasThumbnailCreated = imageService.resizeImage(opaImage);
            String resultFilePath = getRootAttachmentPath() + File.separator + thumbnailPath + File.separator
                    + getThumbnailFileName(originalFile.getName());
            log.debug("checking if the thumbnail is there... in directory " + resultFilePath);
            thumbnailImg = new File(resultFilePath);
            if (!thumbnailImg.exists() || !wasThumbnailCreated) {
                // OPA 6.4 - if the image failed, then don't update the path
                return null;
            }
        } catch (Exception e) {
            throw e;
        }
        log.debug("createThumbnail() - finish");
        return thumbnailImg.getAbsolutePath();
    }

    /**
     * Save the input stream into the destination file
     * 
     * @param iStream
     * @param destinationFile
     * @throws Exception
     */
    public long uploadFile(InputStream iStream, File destinationFile) throws Exception {
        FileOutputStream oStream = null;
        long bytesWritten = 0; // AGS Replacement 2012
        try {
            // write the stream to the specified file
            oStream = new FileOutputStream(destinationFile);
            byte[] buffer = new byte[8192];
            int bytesRead = 0;
            while ((bytesRead = iStream.read(buffer)) != -1) {
                oStream.write(buffer, 0, bytesRead);
                bytesWritten += bytesRead;
            }
        } catch (FileNotFoundException fnfe) {
            throw new Exception("AttachmentUtils: FileNotFoundException " + fnfe.getMessage());
        } catch (IOException ioe) {
            throw new Exception("AttachmentUtils: IOException " + ioe.getMessage());
        } finally {
            // try to close the input stream
            if (iStream != null) {
                try {
                    iStream.close();
                } catch (IOException e) {
                    log.error(e);
                }
            }

            // try to close the output stream
            if (oStream != null) {
                try {
                    oStream.close();
                } catch (IOException e) {
                    log.error(e);
                }
            }
        }

        return bytesWritten;
    }

    /**
     * This method is to handle the user authentication and authorization validation.
     * 
     * @param requestContext
     * @param requestUserId
     * @param response
     * @return true if user has access otherwise false
     */
    public boolean hasAccess(ContainerRequestContext requestContext, int requestUserId, BaseJsonResponse response) {
        try {
            UserInfo userInfo = (UserInfo) requestContext.getProperty("userInfo");
            if (null == userInfo) {
                throw new ValidationException("Access Denied");
            }
            int userId = Integer.parseInt(userInfo.getUserId());
            if (!RequestUtil.isAdmin(userId) && userId != requestUserId) {
                throw new ValidationException("Permission Denied");
            }
        } catch (ValidationException e) {
            log.info("Validation error: " + e);
            response.setSuccess(false);
            response.setMessage(e.getMessage());
            return false;
        } catch (Exception e) {
            log.error("Exception in hasAccess: " + e);
            response.setSuccess(false);
            response.setMessage(e.getMessage());
            return false;
        }
        return true;
    }

    /**
     * Get the last attachment from the list of attachments.
     * 
     * @param dbAttachments
     * @param product
     * @param lastFileName
     * @return last attachment
     */
    public Attachment getLastAttachment(Attachment[] dbAttachments, Product product, String lastFileName) {
        if (dbAttachments != null && dbAttachments.length > 0) {
            int productStatus = product.getApprovalStatusID();
            boolean isImageThumbnailAllowed = !(productStatus == product.getApprovalStatusID()
                    || productStatus == Product.CANCELLED || productStatus == Product.APPROVED_EXTERNALLY);
            if (isImageThumbnailAllowed) {
                Attachment lastAttachment = null;
                for (Attachment attachment : dbAttachments) {
                    if (attachment.getFilename().equals(lastFileName)) {
                        lastAttachment = attachment;
                        break;
                    }
                }
                if (lastAttachment != null) {
                    return lastAttachment;
                }
            }
        }
        return null;
    }

    /**
     * Save original file to disk.
     * 
     * @param bodyParts
     * @param productId
     */
    public void saveOriginalFile(List<FormDataBodyPart> bodyParts, int productId) {
        try {
            if (bodyParts == null || bodyParts.size() == 0) {
                return;
            }
            String dir = getOriginalAttachmentsPath(productId) + File.separator;
            for (FormDataBodyPart part : bodyParts) {
                String fileName = part.getContentDisposition().getFileName();
                if (StringUtils.isNotEmpty(fileName)) {
                    FileOutputStream fos = new FileOutputStream(dir + StringEscapeUtils.unescapeHtml(fileName));
                    fos.write(part.getEntityAs(byte[].class));
                    fos.flush();
                    fos.close();
                }
            }
        } catch (Exception e) {
            log.error("Error in saveOriginalFile, productId: " + productId, e);
            throw new ValidationException("Error while saving file: " + e.getMessage());
        }
    }

    /**
     * Check user has permission to edit the product or not
     * 
     * @param userPermission
     * @return true if user has edit permission otherwise false
     */
    public boolean canEditSubmission(UserPermission userPermission) {
        try {
            Product product = userPermission.getProduct();
            int productIds[] = new int[] { product.getID() };
            int userIds[] = new int[] { userPermission.getUserId() };
            PASearchResultSet[] resultSets = searchEngineDao.searchQuick(productIds, userIds, 1, 1, 1, null,
                    userPermission.getUserId());
            if (resultSets == null || resultSets.length == 0 || resultSets[0] == null
                    || resultSets[0].getSearchItems() == null || resultSets[0].getSearchItems().length == 0
                    || resultSets[0].getSearchItems()[0] == null
                    || resultSets[0].getSearchItems()[0].getProductSummary() == null
                    || resultSets[0].getSearchItems()[0].getProductSummary().getProductID() != userPermission
                            .getProduct().getID()) {
                throw new ValidationException("User doesn't have permission to access the product.");

            }
            Module module = moduleService.getModule(product.getProductTemplateID(), PageTypes.EDIT_CREATE,
                    UserSelectionTypes.LICENSEE, ModuleTypes.ASSET_MANAGER);
            if (module == null) {
                throw new ValidationException("Asset Manager module not found in product template.");
            }

            ProductState state = userPermission.getState();
            if (state == null) {
                throw new ValidationException("Product doesn't have state.");
            }
            int userId = userPermission.getUserId();
            if (state.getCurrentPerformerID() == userId || state.getCurrentStepOwnerID() == userId
                    || userPermission.isActAsManagingEditor() || userPermission.isActAsAgent()) {
                if (userPermission.isActAsAgent()) {
                    userPermission.setShowReadonlyReviewPage((userId != state.getCurrentPerformerID()));
                } else if (ProductUtil.isLineSheet(product.getProductTemplateID())) {
                    int statusId = product.getProductStatusID();
                    boolean isApproved = (statusId == product.getApprovalStatusID()
                            || statusId == Product.LINE_LIST_APPROVED || statusId == Product.APPROVED_EXTERNALLY);
                    userPermission.setShowReadonlyReviewPage(isApproved);
                } else {
                    userPermission.setShowReadonlyReviewPage(false);
                }
            } else if (PermissionUtil.isUserReviewer(product, userId, state)) {
                userPermission.setShowReadonlyReviewPage(false);
            } else {
                userPermission.setShowReadonlyReviewPage(true);
            }
            if (userPermission.isShowReadonlyReviewPage()) {
                throw new ValidationException("User has permission only to view this product.");
            }
        } catch (ValidationException e) {
            throw e;
        } catch (Exception e) {
            log.error("Error in canEditSubmission", e);
            throw new ValidationException("Unknown error while validating user permissions, error: " + e);
        }
        return true;
    }

    public boolean checkForDoubleByteCharacters(String s) {
        boolean doubleByte = false;
        try {
            for (int i = 0; i < s.length(); i++) {
                String test = "" + s.charAt(i);
                byte[] bytes = test.getBytes("UTF-8");
                if (bytes.length > 1) {
                    doubleByte = true;
                }
            }
        } catch (Exception e) {
            //If we throw an error we can't tell
            return false;
        }

        return doubleByte;
    }

}