org.codice.ddf.catalog.transformer.zip.ZipCompression.java Source code

Java tutorial

Introduction

Here is the source code for org.codice.ddf.catalog.transformer.zip.ZipCompression.java

Source

/**
 * Copyright (c) Codice Foundation
 *
 * <p>This is free software: you can redistribute it and/or modify it under the terms of the GNU
 * Lesser General Public License as published by the Free Software Foundation, either version 3 of
 * the License, or any later version.
 *
 * <p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details. A copy of the GNU Lesser General Public
 * License is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package org.codice.ddf.catalog.transformer.zip;

import com.google.common.io.FileBackedOutputStream;
import ddf.catalog.data.BinaryContent;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.Result;
import ddf.catalog.data.impl.BinaryContentImpl;
import ddf.catalog.operation.SourceResponse;
import ddf.catalog.transform.CatalogTransformerException;
import ddf.catalog.transform.MetacardTransformer;
import ddf.catalog.transform.QueryResponseTransformer;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.activation.MimeType;
import javax.activation.MimeTypeParseException;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ZipCompression implements QueryResponseTransformer {

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

    private static final String METACARD_PATH = "metacards" + File.separator;

    private static final String TRANSFORMER_ID = "transformerId";

    private static final int BUFFER_SIZE = 4096;

    private List<ServiceReference> metacardTransformers;

    private BundleContext bundleContext;

    private static MimeType mimeType;

    static {
        try {
            mimeType = new MimeType("application/zip");
        } catch (MimeTypeParseException e) {
            LOGGER.warn("Failed to apply mimetype application/zip");
        }
    }

    public ZipCompression(BundleContext bundleContext, List<ServiceReference> metacardTransformers) {
        this.bundleContext = bundleContext;
        this.metacardTransformers = metacardTransformers;
    }

    /**
     * Transforms a SourceResponse with a list of {@link Metacard}s into a {@link BinaryContent} item
     * with an {@link InputStream}. This transformation expects a key-value pair
     * "fileName"-zipFileName to be present.
     *
     * @param sourceResponse - a SourceResponse with a list of {@link Metacard}s to compress
     * @param arguments - a map of arguments to use for processing. This method expects "fileName" to
     *     be set
     * @return - a {@link BinaryContent} item with the {@link InputStream} for the Zip file
     * @throws CatalogTransformerException when the transformation fails
     */
    @Override
    public BinaryContent transform(SourceResponse sourceResponse, Map<String, Serializable> arguments)
            throws CatalogTransformerException {

        if (sourceResponse == null || CollectionUtils.isEmpty(sourceResponse.getResults())) {
            throw new CatalogTransformerException(
                    "The source response does not contain any metacards to transform.");
        }

        if (arguments.get(TRANSFORMER_ID) == null) {
            throw new CatalogTransformerException("Transformer ID cannot be null");
        }

        String transformerId = arguments.getOrDefault(TRANSFORMER_ID, "").toString();

        if (StringUtils.isBlank(transformerId)) {
            throw new CatalogTransformerException("A valid transformer ID must be provided.");
        }

        InputStream inputStream = createZip(sourceResponse, transformerId);

        return new BinaryContentImpl(inputStream, mimeType);
    }

    private InputStream createZip(SourceResponse sourceResponse, String transformerId)
            throws CatalogTransformerException {
        ServiceReference<MetacardTransformer> serviceRef = getTransformerServiceReference(transformerId);
        MetacardTransformer transformer = bundleContext.getService(serviceRef);

        String extension = getFileExtensionFromService(serviceRef);

        if (StringUtils.isNotBlank(extension)) {
            extension = "." + extension;
        }

        try (FileBackedOutputStream fileBackedOutputStream = new FileBackedOutputStream(BUFFER_SIZE);
                ZipOutputStream zipOutputStream = new ZipOutputStream(fileBackedOutputStream)) {

            for (Result result : sourceResponse.getResults()) {
                Metacard metacard = result.getMetacard();

                BinaryContent binaryContent = getTransformedMetacard(metacard, Collections.emptyMap(), transformer);

                if (binaryContent != null) {
                    ZipEntry entry = new ZipEntry(METACARD_PATH + metacard.getId() + extension);

                    zipOutputStream.putNextEntry(entry);
                    zipOutputStream.write(binaryContent.getByteArray());
                    zipOutputStream.closeEntry();
                } else {
                    LOGGER.debug("Metacard with id [{}] was not added to zip file", metacard.getId());
                }
            }

            return fileBackedOutputStream.asByteSource().openStream();

        } catch (IOException e) {
            throw new CatalogTransformerException("An error occurred while initializing or closing output stream",
                    e);
        }
    }

    private BinaryContent getTransformedMetacard(Metacard metacard, Map<String, Serializable> arguments,
            MetacardTransformer transformer) {
        try {
            return transformer.transform(metacard, arguments);
        } catch (CatalogTransformerException e) {
            LOGGER.debug("Failed to transform metacard with id [{}]", metacard.getId(), e);
            return null;
        }
    }

    private String getFileExtensionFromService(ServiceReference<MetacardTransformer> serviceRef) {
        Object mimeTypeProperty = serviceRef.getProperty("mime-type");

        if (mimeTypeProperty == null) {
            return "";
        }

        String mimeTypeStr = mimeTypeProperty.toString();

        try {
            MimeType exportMimeType = new MimeType(mimeTypeStr);
            return exportMimeType.getSubType();
        } catch (MimeTypeParseException e) {
            LOGGER.debug("Failed to parse mime type {}", mimeTypeStr, e);
            return "";
        }
    }

    private ServiceReference getTransformerServiceReference(String transformerId)
            throws CatalogTransformerException {
        return metacardTransformers.stream()
                .filter(serviceRef -> transformerId.equals(serviceRef.getProperty("id"))).findFirst()
                .orElseThrow(() -> new CatalogTransformerException(
                        "The metacard transformer with ID " + transformerId + " could not be found."));
    }
}