All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lionbridge.content.sdk.utilities.ZipUtils Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
package com.lionbridge.content.sdk.utilities;

import com.lionbridge.content.sdk.ContentAPIException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipUtils {

    private final Logger LOGGER = LoggerFactory.getLogger(ZipUtils.class);

	private String zipFilePath = null;

	public String getZipFilePath() {
		return this.zipFilePath;
	}

	public void setZipFilePath(final String pathIn) {
		this.zipFilePath = pathIn;
	}

	/**
	 * Create a new ZipUtils instance and set the zip file path accordingly.
	 * @param pathIn Set the zip file path to this if it is set.
	 * @param strTranslationJobID The ID of the Translation JOB
	 */
	public ZipUtils(final String pathIn, final String strTranslationJobID) {

        if (null != pathIn && !pathIn.trim().isEmpty()) {
            this.setZipFilePath(pathIn);
        }

		if(null == this.zipFilePath) {
			this.setZipFilePath(this.createZipFilePath("/tmp", strTranslationJobID, true, true));
		}
	}

	/**
	 * Create a zip file path.
	 * @param rootFolder The folder in which to create the zip folder
	 * @param strTranslationJobID The job ID to parse (we only want the last part)
	 * @param includeDate flag to select whether to include the date in the path
	 * @param includeRandomizer flag to select whether to add a randomizer to the path
	 * @return the path in string form
	 */
	public String createZipFilePath(final String rootFolder,
			final String strTranslationJobID, boolean includeDate, boolean includeRandomizer) {

		String newZipFilePath;

    	// get the job ID name (trimming the path off of it)
		String justJobName = "";
		try {
			final String[] jobIdParts = strTranslationJobID.split("/");
    		if(null != jobIdParts) {
    			// ensure there is at least one part from the split
    			if(0 < jobIdParts.length) {
        			justJobName = jobIdParts[jobIdParts.length - 1];
    			} else {
    				this.LOGGER.debug("JobID: split of {} returned no objects.", strTranslationJobID);
    			}
    		} else {
    			this.LOGGER.debug("JobID: split of {} returned null.", strTranslationJobID);
    		}
		} catch (Exception e1) {
			this.LOGGER.debug("JobID split exception", e1);
		}

		// if we couldn't parse the Job ID, just use this as a default.
		// Force date and randomizer to be added.
		if(justJobName.trim().isEmpty()) {
			justJobName = "OnDemandFiles";
			includeDate = true;
			includeRandomizer = true;
		}

		// now get the current time to append to the job name
		String curTimeString = "";
		if(includeDate) {
			final Date curTime = new Date();
			curTimeString = "_" + (new SimpleDateFormat("yyyyMMddHHmmss")).format(curTime);
		}

		// now generate a random 6 digit number to append after that.
		String randomizerString = "";
		if(includeRandomizer) {
			Random randomGenerator = new Random();
			final int randomizer = randomGenerator.nextInt(1000000);
			randomizerString = "_" + String.format("%06d", randomizer);
		}

		// now build the path. Should look something like /tmp/jobname_20160401152436_013579 if both options are set.
		newZipFilePath = rootFolder + "/" + justJobName + curTimeString + randomizerString;
		this.LOGGER.debug("addFileToZipFolder: Path created: {}", newZipFilePath);
		return newZipFilePath;
	}

	/**
	 * Create a zip file with all of the contents from the path saved in this class.
	 * The file name will be (zipFilePath).(serviceId).zip.  If serviceId is null
	 * or blank, it will be (zipFilePath).zip
     * @param serviceId The ID of the service being used.
	 * @return The completed zip file
	 * @throws ContentAPIException An exception containing any API errors
	 */
	public File createZipFile(final String serviceId) throws ContentAPIException {
    	try {
        	// create the zip file and folder objects
    		String finalZipName = this.zipFilePath;
    		String finalZipPath = this.zipFilePath;
            if (null != serviceId && !serviceId.trim().isEmpty()) {
                finalZipName += "." + serviceId;
                finalZipPath += "/" + serviceId;
            }
        	File zipFile = new File(finalZipName + ".zip");
        	File zipFolder = new File(finalZipPath);
        	ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile));

        	// list the files and loop through them
        	File[] folderList = zipFolder.listFiles();
        	if(null != folderList) {
        		StringBuilder dirContents = new StringBuilder();
        		for(File singleFile : folderList) {
        			dirContents.append("\n\t").append(singleFile.getName());
        			if(singleFile.isFile()) {
            			// create a zip entry for this file and start adding it
            			ZipEntry fileToZip = new ZipEntry(singleFile.getName());
                		zipOut.putNextEntry(fileToZip);

                		try {
                			// copy the file into the zip using a byte stream
                    		final FileInputStream inputFileStream = new FileInputStream(singleFile);
                    		ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
                    		int byteRead = inputFileStream.read();
                    		while(0 <= byteRead) {
                    			byteStream.write(byteRead);
                    			byteRead = inputFileStream.read();
                    		}
                    		final byte[] fileData = byteStream.toByteArray();
                    		this.LOGGER.debug("addFileToZipFolder: Read {} bytes from input file {}/{}" +
                    				fileData.length, finalZipPath, singleFile.getName());
                    		zipOut.write(fileData, 0, fileData.length);

                    		// close the input stream and the zip entry to reset for any more files
                    		inputFileStream.close();
                    		zipOut.closeEntry();
                		} catch (Exception e1) {
                			this.LOGGER.error("Got exception adding data to zip. {}", e1.getMessage(), e1);
                			e1.printStackTrace();
                		}
        			}
        		}
        		this.LOGGER.trace("Directory list for {}: {}", this.zipFilePath, dirContents);
        	}

        	// for cleanup purposes, close the ZipOutputStream
    		zipOut.close();

    		return zipFile;
    	} catch (Exception e) {
    		this.LOGGER.error("createZipFile EXCEPTION", e);
    		e.printStackTrace();
    		throw new ContentAPIException(e);
    	}
	}

	/**
	 * Determine if the extension from an input file name matches one of the items
	 * in a list. Note that this can pick up some "inside" extensions, like
	 * filename.txt.save will match TXT or SAVE.
	 * @param fileName Name to parse
	 * @param extensions List of extensions to search for
	 * @return True if filename matches the extension. False if not.
	 */
	private boolean fileMatchesExtensions(final String fileName, final List extensions) {
		if(fileName.contains(".")) {
			String[] fileNameParts = fileName.split("\\.");
			for(String fileNamePart : fileNameParts) {
				this.LOGGER.trace("fileMatchesExtensions: part {}, extensions {}",
						fileNamePart, extensions.toString());
				if(extensions.contains(fileNamePart.trim().toUpperCase())) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * Move files into the applicable service ID subfolder
	 * @param serviceMap map containing file extensions by serviceID
	 */
	public void arrangeFilesByService(final HashMap> serviceMap) {

		// Make sure the folder exists for the zip file
    	File zipFolder = new File(this.zipFilePath);
    	if(!zipFolder.exists()) {
    		zipFolder.mkdir();
    	}

		// loop through all of the service IDs
		for(String serviceId : serviceMap.keySet()) {
			// create a subdirectory for each service ID
	    	File serviceFolder = new File(this.zipFilePath + "/" + serviceId);
	    	if(!serviceFolder.exists()) {
	    		serviceFolder.mkdirs();
	    	}

	    	// find all of the files matching the extensions in the map for this service
	    	// and move each file into this folder
        	File[] directoryList = zipFolder.listFiles();
        	if(null != directoryList) {
        		String dirContents = "";
        		for(File singleFile : directoryList) {
        			dirContents += "\n\t" + singleFile.getPath();

        			// get file extension and compare it to the map
        			if(singleFile.isFile()) {
            			if(this.fileMatchesExtensions(singleFile.getName(), serviceMap.get(serviceId))) {
            				dirContents += " (MOVED)";
                        	File fileCopy = new File(this.zipFilePath + "/" + serviceId + "/" + singleFile.getName());
                        	try {
                        		Files.move(FileSystems.getDefault().getPath(singleFile.getPath()),
        								FileSystems.getDefault().getPath(fileCopy.getPath()),
        								StandardCopyOption.REPLACE_EXISTING);
        					} catch (IOException e) {
        						this.LOGGER.error("Got I/O Exception moving file {}",
        								singleFile.getName(), e);
        					}
            			} else {
            				this.LOGGER.debug("arrangeFilesByService: File name {}" +
            						" did not match extensions.", singleFile.getName());
            			}
        			}
        		}
        		this.LOGGER.debug("arrangeFilesByService: Directory list for {}: {}", this.zipFilePath, dirContents);
        	} else {
        		this.LOGGER.debug("arrangeFilesByService: Directory list for {} is null.", this.zipFilePath);
        	}


		}
	}

	/**
	 * Add a specified file to the zip folder for an input job ID. The files
	 * will be zipped up in a separate process.
	 * @param inputFile the file to add to the zip folder
	 * @throws ContentAPIException An exception containing any API errors
	 */
	public void addFileToZipFolder(File inputFile) throws ContentAPIException {
    	try {
        	// Make sure the folder exists for the zip file
        	File zipFolder = new File(this.zipFilePath);
        	if(!zipFolder.exists()) {
        		zipFolder.mkdir();
        	}

        	// Copy the file into the zip folder
        	File fileCopy = new File(this.zipFilePath + "/" + inputFile.getName());
        	Files.copy(FileSystems.getDefault().getPath(inputFile.getPath()),
        			FileSystems.getDefault().getPath(fileCopy.getPath()),
        			StandardCopyOption.REPLACE_EXISTING);

    	} catch (Exception e) {
    		this.LOGGER.error("addFileToZipFolder EXCEPTION: ", e);
    		throw new ContentAPIException(e);
    	}
	}

	/**
	 * Extract all of the files from the specified zip file into an extract folder
	 * @param zipFile Zip file to process
	 * @param extractDir subdirectory to extract to - will create a subdirectory
	 * with this name in the same folder as the input zip file
	 * @return The path of the extracted file
	 */
	public static String extractFilesFromZip(final File zipFile, final String extractDir) {
        try {
			ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFile.getPath()));
			ZipEntry entry = zipIn.getNextEntry();
            final String folderPath = zipFile.getParent() + File.separator + extractDir;
            final File extractFolder = new File(folderPath);
            if(!extractFolder.exists()) {
            	extractFolder.mkdirs();
            }
			// iterates over entries in the zip file
			while (null != entry) {
			    if (!entry.isDirectory()) {
			        // if the entry is a file, extracts it
		            final String filePath = folderPath + File.separator + entry.getName();
	                extractFile(filePath);
			    }
			    zipIn.closeEntry();
			    entry = zipIn.getNextEntry();
			}
			zipIn.close();

			return folderPath;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

        return null;
	}

    private static void extractFile(String filePath) throws IOException {
    	File zipSubfile = new File(filePath);
    	File zipSubfileSubfolder = new File(zipSubfile.getParent());
    	if(!zipSubfileSubfolder.exists()) {
    		zipSubfileSubfolder.mkdirs();
    	}
        FileOutputStream fileStream = new FileOutputStream(zipSubfile);
        fileStream.close();
    }

	private class ZipFolderVisitor extends SimpleFileVisitor {
		@Override
		public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
			ZipUtils.this.LOGGER.debug("postVisitDirectory: Deleting directory {}", dir.toString());
			try {
				Files.delete(dir);
			} catch (IOException e) {
				ZipUtils.this.LOGGER.error("postVisitDirectory: EXCEPTION deleting directory {}",
						dir.toString(), e);
				throw e;
			}
			return FileVisitResult.CONTINUE;
		}

		@Override
		public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
			return FileVisitResult.CONTINUE;
		}

		@Override
		public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
			ZipUtils.this.LOGGER.debug("visitFile: Deleting file {}", file.toString());
			try {
				Files.delete(file);
			} catch (IOException e) {
				ZipUtils.this.LOGGER.error("visitFile: EXCEPTION deleting file {}",
						file.toString(), e);
				throw e;
			}
			return FileVisitResult.CONTINUE;
		}

		@Override
		public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
			return FileVisitResult.CONTINUE;
		}

	}

	/**
	 * Delete the directory created at the path specified in zipFilePath.
	 * Then delete the zip file if specified by the caller.
	 * @param deleteZip if set to true, delete the zip file with the same name.
	 */
	public void cleanUpZipFileAndFolder(final boolean deleteZip) {

		File zipFolder = new File(this.zipFilePath);

    	// print the contents of the folder that was already zipped
    	File[] directoryList = zipFolder.listFiles();
    	if(null != directoryList) {
    		for(File singleFile : directoryList) {
    			try {
    				if(singleFile.isFile()) {
    					this.LOGGER.debug("cleanUpZipFileAndFolder Deleting file {}", singleFile.getPath());
    					singleFile.delete();
    				} else {
    					this.LOGGER.debug("cleanUpZipFileAndFolder object {} is not a file.",
								singleFile.getPath());
    				}
				} catch (Exception e) {
					this.LOGGER.error("cleanUpZipFileAndFolder file delete EXCEPTION", e);
				}
    		}
    	}

    	directoryList = zipFolder.listFiles();
        if (null != directoryList && 0 < directoryList.length) {
            try {
                Files.walkFileTree(zipFolder.toPath(), new ZipFolderVisitor());
            } catch (IOException e1) {
                this.LOGGER.error("cleanUpZipFileAndFolder walk file tree EXCEPTION", e1);
            }
        }

    	// double check the directory to ensure it's empty (so we can delete it too)
    	if(zipFolder.exists()) {
        	File[] directoryListAfter = zipFolder.listFiles();
        	boolean directoryEmpty = true;
        	if(null != directoryListAfter) {
        		for(File singleFile : directoryListAfter) {
        			if(singleFile.isFile() || singleFile.isDirectory()) {
        				directoryEmpty = false;
        				break;
        			}
        		}
        	}

        	if(directoryEmpty) {
        		try {
    				zipFolder.delete();
    			} catch (Exception e) {
    				this.LOGGER.error("cleanUpZipFileAndFolder folder delete EXCEPTION", e);
    			}
        	}
    	}

    	if(deleteZip) {
    		this.LOGGER.debug("Will delete file " + this.zipFilePath + ".zip.");
    		try {
				File zipFile = new File(this.zipFilePath + ".zip");
				zipFile.delete();
			} catch (Exception e) {
				this.LOGGER.error("cleanUpZipFileAndFolder Zip delete EXCEPTION", e);
			}
    	}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy