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.zip.ZipEntry;
024import java.util.zip.ZipOutputStream;
025
026
027/**
028 * Compresses a file using Zip compression.
029 */
030public 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}