001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017package org.apache.logging.log4j.core.appender.rolling.action;
018
019import java.io.File;
020import java.io.FileInputStream;
021import java.io.FileOutputStream;
022import java.io.IOException;
023import java.util.Objects;
024import java.util.zip.ZipEntry;
025import java.util.zip.ZipOutputStream;
026
027
028/**
029 * Compresses a file using Zip compression.
030 */
031public final class ZipCompressAction extends AbstractAction {
032
033    private static final int BUF_SIZE = 8102;
034
035    /**
036     * Source file.
037     */
038    private final File source;
039
040    /**
041     * Destination file.
042     */
043    private final File destination;
044
045    /**
046     * If true, attempts to delete file on completion.
047     */
048    private final boolean deleteSource;
049
050    /**
051     * Compression level.
052     */
053    private final int level;
054
055    /**
056     * Creates new instance of GzCompressAction.
057     *
058     * @param source       file to compress, may not be null.
059     * @param destination  compressed file, may not be null.
060     * @param deleteSource if true, attempt to delete file on completion.  Failure to delete
061     *                     does not cause an exception to be thrown or affect return value.
062     * @param level TODO
063     */
064    public ZipCompressAction(final File source, final File destination, final boolean deleteSource, final int level) {
065        Objects.requireNonNull(source, "source");
066        Objects.requireNonNull(destination, "destination");
067
068        this.source = source;
069        this.destination = destination;
070        this.deleteSource = deleteSource;
071        this.level = level;
072    }
073
074    /**
075     * Compresses.
076     *
077     * @return true if successfully compressed.
078     * @throws IOException on IO exception.
079     */
080    @Override
081    public boolean execute() throws IOException {
082        return execute(source, destination, deleteSource, level);
083    }
084
085    /**
086     * Compresses a file.
087     *
088     * @param source       file to compress, may not be null.
089     * @param destination  compressed file, may not be null.
090     * @param deleteSource if true, attempt to delete file on completion.  Failure to delete
091     *                     does not cause an exception to be thrown or affect return value.
092     * @param level the compression level
093     * @return true if source file compressed.
094     * @throws IOException on IO exception.
095     */
096    public static boolean execute(final File source, final File destination, final boolean deleteSource, final int level)
097            throws IOException {
098        if (source.exists()) {
099            try (final FileInputStream fis = new FileInputStream(source);
100                    final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(destination))) {
101                zos.setLevel(level);
102
103                final ZipEntry zipEntry = new ZipEntry(source.getName());
104                zos.putNextEntry(zipEntry);
105
106                final byte[] inbuf = new byte[BUF_SIZE];
107                int n;
108
109                while ((n = fis.read(inbuf)) != -1) {
110                    zos.write(inbuf, 0, n);
111                }
112            }
113
114            if (deleteSource && !source.delete()) {
115                LOGGER.warn("Unable to delete " + source.toString() + '.');
116            }
117
118            return true;
119        }
120
121        return false;
122    }
123
124    /**
125     * Captures exception.
126     *
127     * @param ex exception.
128     */
129    @Override
130    protected void reportException(final Exception ex) {
131        LOGGER.warn("Exception during compression of '" + source.toString() + "'.", ex);
132    }
133
134    @Override
135    public String toString() {
136        return ZipCompressAction.class.getSimpleName() + '[' + source + " to " + destination //
137                + ", level=" + level + ", deleteSource=" + deleteSource + ']';
138    }
139}