org.opentestsystem.authoring.testitembank.service.impl.ApipZipOutputFileBuilderService.java Source code

Java tutorial

Introduction

Here is the source code for org.opentestsystem.authoring.testitembank.service.impl.ApipZipOutputFileBuilderService.java

Source

/*******************************************************************************
 * Educational Online Test Delivery System 
 * Copyright (c) 2014 American Institutes for Research
 *   
 * Distributed under the AIR Open Source License, Version 1.0 
 * See accompanying file AIR-License-1_0.txt or at
 * http://www.smarterapp.org/documents/American_Institutes_for_Research_Open_Source_Software_License.pdf
 ******************************************************************************/
package org.opentestsystem.authoring.testitembank.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import javax.xml.bind.JAXBException;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.opentestsystem.authoring.testitembank.apipzip.domain.ApipManifest;
import org.opentestsystem.authoring.testitembank.domain.ItemHistory;
import org.opentestsystem.authoring.testitembank.persistence.GridFsRepository;
import org.opentestsystem.authoring.testitembank.service.ZipOutputFileBuilderService;
import org.opentestsystem.authoring.testitembank.service.ZipXMLService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import com.google.common.collect.Lists;
import com.mongodb.gridfs.GridFSDBFile;

public class ApipZipOutputFileBuilderService implements ZipOutputFileBuilderService {

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

    private static final String RELATIVE_MANIFEST_PATH = "/imsmanifest.xml";

    @Autowired
    private GridFsRepository gridFsRepository;

    @Autowired
    private ZipXMLService zipXMLService;

    @Value(value = "${tib.file.pathname:}${tib.file.exportfolder:/tib-exports}")
    private String localExportDirectory;

    @Override
    public File createExportFile(final String exportSetId, final List<ItemHistory> items)
            throws IOException, JAXBException {
        final String localDirectoryPath = localExportDirectory + "/" + exportSetId;
        final List<ApipManifest> manifests = Lists.newArrayList();

        // build export file locally
        for (final ItemHistory item : items) {
            final GridFSDBFile gridfsFile = gridFsRepository.getById(item.getItemZipGridId());
            unzipToLocalDirectory(localDirectoryPath, gridfsFile);

            // read in this item's manifest file
            final InputStream manifestFile = new FileInputStream(localDirectoryPath + RELATIVE_MANIFEST_PATH);
            manifests.add(zipXMLService.extractManifestFromXML(manifestFile));
            IOUtils.closeQuietly(manifestFile);
        }

        final ApipManifest consolidatedManifest = zipXMLService.consolidateManifests(exportSetId, manifests);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(localDirectoryPath + RELATIVE_MANIFEST_PATH);
            zipXMLService.writeToManifestToOutputStream(consolidatedManifest, fos);
        } finally {
            closeAndFlushQuietly(fos);
        }

        return createZipFromLocalDirectory(new File(localDirectoryPath), localDirectoryPath + ".zip");
    }

    private static final void unzipToLocalDirectory(final String parentDir, final GridFSDBFile zipFile)
            throws IOException {
        ZipInputStream zipInputStream = null;
        try {
            zipInputStream = new ZipInputStream(zipFile.getInputStream());

            ZipEntry nextEntry = null;
            while ((nextEntry = zipInputStream.getNextEntry()) != null) {
                if (!nextEntry.isDirectory()) {
                    // create local file
                    final File f = new File(parentDir + "/" + nextEntry.getName());
                    f.getParentFile().mkdirs();
                    f.createNewFile();

                    int len = 0;
                    final byte[] buff = new byte[1024];

                    // write entry to file
                    FileOutputStream fos = null;
                    try {
                        fos = new FileOutputStream(f);
                        while ((len = zipInputStream.read(buff)) > 0) {
                            fos.write(buff, 0, len);
                        }
                    } catch (final FileNotFoundException e) {
                        LOGGER.error("unexcepted FileNotFoundException: ", e);
                    } finally {
                        closeAndFlushQuietly(fos);
                        closeEntryQuiety(zipInputStream);
                    }
                }
            }
        } finally {
            IOUtils.closeQuietly(zipInputStream);
        }
    }

    private static final File createZipFromLocalDirectory(final File sourceDirectory, final String targetZipName)
            throws IOException {
        final Collection<File> filesToZip = FileUtils.listFiles(sourceDirectory, TrueFileFilter.INSTANCE,
                TrueFileFilter.INSTANCE);

        FileOutputStream fout = null;
        ZipOutputStream zout = null;
        final File targetZip = new File(targetZipName);
        try {
            fout = new FileOutputStream(targetZip);
            zout = new ZipOutputStream(fout);

            for (final File file : filesToZip) {
                FileInputStream fin = null;
                try {
                    fin = new FileInputStream(file);
                    zout.putNextEntry(new ZipEntry(getRelativePath(file, sourceDirectory)));

                    final byte[] buffer = new byte[1024];
                    int length;
                    while ((length = fin.read(buffer)) > 0) {
                        zout.write(buffer, 0, length);
                    }
                } finally {
                    IOUtils.closeQuietly(fin);
                    closeEntryQuiety(zout);
                }
            }
        } catch (final FileNotFoundException e) {
            LOGGER.error("unexcepted FileNotFoundException: ", e);
        } finally {
            closeAndFlushQuietly(zout);
            closeAndFlushQuietly(fout);
        }

        return targetZip;
    }

    private static final String getRelativePath(final File file, final File parentDir) {
        final Path filePath = Paths.get(file.getAbsolutePath());
        final Path parentDirPath = Paths.get(parentDir.getAbsolutePath());
        return parentDirPath.relativize(filePath).toString();
    }

    private static final void closeAndFlushQuietly(final OutputStream os) {
        try {
            if (os != null) {
                os.flush();
                os.close();
            }
        } catch (final IOException e) {
            LOGGER.error("error closing output stream.", e);
        }
    }

    private static final void closeEntryQuiety(final ZipOutputStream zos) {
        try {
            if (zos != null) {
                zos.closeEntry();
            }
        } catch (final IOException e) {
            LOGGER.error("error closing zip output stream entry.", e);
        }
    }

    private static final void closeEntryQuiety(final ZipInputStream zis) {
        try {
            if (zis != null) {
                zis.closeEntry();
            }
        } catch (final IOException e) {
            LOGGER.error("error closing zip input stream entry.", e);
        }
    }
}