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 * Compresses a file using Zip compression.
029 */
030public final class ZipCompressAction extends AbstractAction {
031
032    private static final int BUF_SIZE = 8192;
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, attempts 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     * Creates 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 does not cause an exception
060     *            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        Objects.requireNonNull(source, "source");
065        Objects.requireNonNull(destination, "destination");
066
067        this.source = source;
068        this.destination = destination;
069        this.deleteSource = deleteSource;
070        this.level = level;
071    }
072
073    /**
074     * Compresses.
075     *
076     * @return true if successfully compressed.
077     * @throws IOException on IO exception.
078     */
079    @Override
080    public boolean execute() throws IOException {
081        return execute(source, destination, deleteSource, level);
082    }
083
084    /**
085     * Compresses a file.
086     *
087     * @param source file to compress, may not be null.
088     * @param destination compressed file, may not be null.
089     * @param deleteSource if true, attempt to delete file on completion. Failure to delete does not cause an exception
090     *            to be thrown or affect return value.
091     * @param level the compression level
092     * @return true if source file compressed.
093     * @throws IOException on IO exception.
094     */
095    public static boolean execute(final File source, final File destination, final boolean deleteSource,
096            final int level) throws IOException {
097        if (source.exists()) {
098            try (final FileInputStream fis = new FileInputStream(source);
099                    final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(destination))) {
100                zos.setLevel(level);
101
102                final ZipEntry zipEntry = new ZipEntry(source.getName());
103                zos.putNextEntry(zipEntry);
104
105                final byte[] inbuf = new byte[BUF_SIZE];
106                int n;
107
108                while ((n = fis.read(inbuf)) != -1) {
109                    zos.write(inbuf, 0, n);
110                }
111            }
112
113            if (deleteSource && !source.delete()) {
114                LOGGER.warn("Unable to delete " + source.toString() + '.');
115            }
116
117            return true;
118        }
119
120        return false;
121    }
122
123    /**
124     * Captures exception.
125     *
126     * @param ex exception.
127     */
128    @Override
129    protected void reportException(final Exception ex) {
130        LOGGER.warn("Exception during compression of '" + source.toString() + "'.", ex);
131    }
132
133    @Override
134    public String toString() {
135        return ZipCompressAction.class.getSimpleName() + '[' + source + " to " + destination
136                + ", level=" + level + ", deleteSource=" + deleteSource + ']';
137    }
138
139    public File getSource() {
140        return source;
141    }
142
143    public File getDestination() {
144        return destination;
145    }
146
147    public boolean isDeleteSource() {
148        return deleteSource;
149    }
150
151    public int getLevel() {
152        return level;
153    }
154}