    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     */
    017    package org.apache.logging.log4j.core.appender.rolling.action;
    018
    019    import java.io.File;
    020    import java.io.FileInputStream;
    021    import java.io.FileOutputStream;
    022    import java.io.IOException;
    023    import java.util.zip.ZipEntry;
    024    import java.util.zip.ZipOutputStream;
    025
    026
    027    /**
    028     * Compresses a file using Zip compression.
    029     */
    030    public final class ZipCompressAction extends AbstractAction {
    031
    032        private static final int BUF_SIZE = 8102;
    033
    034        /**
    035         * Source file.
    036         */
    037        private final File source;
    038
    039        /**
    040         * Destination file.
    041         */
    042        private final File destination;
    043
    044        /**
    045         * If true, attempt to delete file on completion.
    046         */
    047        private final boolean deleteSource;
    048
    049        /**
    050         * Compression level.
    051         */
    052        private final int level;
    053
    054        /**
    055         * Create new instance of GzCompressAction.
    056         *
    057         * @param source       file to compress, may not be null.
    058         * @param destination  compressed file, may not be null.
    059         * @param deleteSource if true, attempt to delete file on completion.  Failure to delete
    060         *                     does not cause an exception to be thrown or affect return value.
    061         * @param level TODO
    062         */
    063        public ZipCompressAction(final File source, final File destination, final boolean deleteSource, final int level) {
    064            if (source == null) {
    065                throw new NullPointerException("source");
    066            }
    067
    068            if (destination == null) {
    069                throw new NullPointerException("destination");
    070            }
    071
    072            this.source = source;
    073            this.destination = destination;
    074            this.deleteSource = deleteSource;
    075            this.level = level;
    076        }
    077
    078        /**
    079         * Compress.
    080         *
    081         * @return true if successfully compressed.
    082         * @throws IOException on IO exception.
    083         */
    084        @Override
    085        public boolean execute() throws IOException {
    086            return execute(source, destination, deleteSource, level);
    087        }
    088
    089        /**
    090         * Compress a file.
    091         *
    092         * @param source       file to compress, may not be null.
    093         * @param destination  compressed file, may not be null.
    094         * @param deleteSource if true, attempt to delete file on completion.  Failure to delete
    095         *                     does not cause an exception to be thrown or affect return value.
    096         * @param level the compression level
    097         * @return true if source file compressed.
    098         * @throws IOException on IO exception.
    099         */
    100        public static boolean execute(final File source, final File destination, final boolean deleteSource, final int level)
    101            throws IOException {
    102            if (source.exists()) {
    103                final FileInputStream fis = new FileInputStream(source);
    104                final FileOutputStream fos = new FileOutputStream(destination);
    105                final ZipOutputStream zos = new ZipOutputStream(fos);
    106                zos.setLevel(level);
    107
    108                final ZipEntry zipEntry = new ZipEntry(source.getName());
    109                zos.putNextEntry(zipEntry);
    110
    111                final byte[] inbuf = new byte[BUF_SIZE];
    112                int n;
    113
    114                while ((n = fis.read(inbuf)) != -1) {
    115                    zos.write(inbuf, 0, n);
    116                }
    117
    118                zos.close();
    119                fis.close();
    120
    121                if (deleteSource && !source.delete()) {
    122                    LOGGER.warn("Unable to delete " + source.toString() + '.');
    123                }
    124
    125                return true;
    126            }
    127
    128            return false;
    129        }
    130
    131        /**
    132         * Capture exception.
    133         *
    134         * @param ex exception.
    135         */
    136        @Override
    137        protected void reportException(final Exception ex) {
    138            LOGGER.warn("Exception during compression of '" + source.toString() + "'.", ex);
    139        }
    140
    141        @Override
    142        public String toString() {
    143            return ZipCompressAction.class.getSimpleName() + '[' + source + " to " + destination //
    144                    + ", level=" + level + ", deleteSource=" + deleteSource + ']';
    145        }
    146    }