de.langmi.spring.batch.examples.readers.file.zip.ZipMultiResourceItemReader.java Source code

Java tutorial

Introduction

Here is the source code for de.langmi.spring.batch.examples.readers.file.zip.ZipMultiResourceItemReader.java

Source

/**
 * Copyright 2011 Michael R. Lange <michael.r.lange@langmi.de>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.langmi.spring.batch.examples.readers.file.zip;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.file.MultiResourceItemReader;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;

/**
 * Multi Resource Item Reader capable of reading zip archive files. Extracts only
 * the contained files, ignores directories.
 * <br />
 * Falls back to normal MultiResourceItemReader behaviour if no archive is set.
 *
 * @author Michael R. Lange <michael.r.lange@langmi.de>
 * @param <T> 
 */
public class ZipMultiResourceItemReader<T> extends MultiResourceItemReader<T> {

    private static final Logger LOG = LoggerFactory.getLogger(ZipMultiResourceItemReader.class);
    private Resource[] archives;
    private ZipFile[] zipFiles;

    /**
     * Tries to extract all files in the archives and adds them as resources to
     * the normal MultiResourceItemReader. Overwrites the Comparator from
     * the super class to get it working with itemstreams.
     *
     * @param executionContext
     * @throws ItemStreamException 
     */
    @Override
    public void open(ExecutionContext executionContext) throws ItemStreamException {
        // really used with archives?
        if (archives != null) {
            // overwrite the comparator to use description
            // instead of filename, the itemStream can only
            // have that description
            this.setComparator(new Comparator<Resource>() {

                /** Compares resource descriptions. */
                @Override
                public int compare(Resource r1, Resource r2) {
                    return r1.getDescription().compareTo(r2.getDescription());
                }
            });
            // get the inputStreams from all files inside the archives
            zipFiles = new ZipFile[archives.length];
            List<Resource> extractedResources = new ArrayList<Resource>();
            try {
                for (int i = 0; i < archives.length; i++) {
                    // find files inside the current zip resource
                    zipFiles[i] = new ZipFile(archives[i].getFile());
                    extractFiles(zipFiles[i], extractedResources);
                }
            } catch (Exception ex) {
                throw new ItemStreamException(ex);
            }
            // propagate extracted resources
            this.setResources(extractedResources.toArray(new Resource[extractedResources.size()]));
        }
        super.open(executionContext);
    }

    /**
     * Calls super.close() and tries to close all used zip files.
     *
     * @throws ItemStreamException 
     */
    @Override
    public void close() throws ItemStreamException {
        super.close();
        // try to close all used zipfiles
        if (zipFiles != null) {
            for (int i = 0; i < zipFiles.length; i++) {
                try {
                    zipFiles[i].close();
                } catch (IOException ex) {
                    throw new ItemStreamException(ex);
                }
            }
        }
    }

    /**
     * Extract only files from the zip archive.
     *
     * @param currentZipFile
     * @param extractedResources
     * @throws IOException 
     */
    private static void extractFiles(final ZipFile currentZipFile, final List<Resource> extractedResources)
            throws IOException {
        Enumeration<? extends ZipEntry> zipEntryEnum = currentZipFile.entries();
        while (zipEntryEnum.hasMoreElements()) {
            ZipEntry zipEntry = zipEntryEnum.nextElement();
            LOG.info("extracting:" + zipEntry.getName());
            // traverse directories
            if (!zipEntry.isDirectory()) {
                // add inputStream
                extractedResources
                        .add(new InputStreamResource(currentZipFile.getInputStream(zipEntry), zipEntry.getName()));
                LOG.info("using extracted file:" + zipEntry.getName());
            }
        }
    }

    /**
     * Set archive files with normal Spring resources pattern, if not set, the
     * class will fallback to normal MultiResourceItemReader behaviour.
     *
     * @param archives 
     */
    public void setArchives(Resource[] archives) {
        this.archives = archives;
    }
}