001/* 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2026, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v2.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.core.rolling.helper; 015 016import java.util.concurrent.ExecutorService; 017import java.util.concurrent.Future; 018 019import ch.qos.logback.core.rolling.RolloverFailure; 020import ch.qos.logback.core.spi.ContextAwareBase; 021import ch.qos.logback.core.util.DynamicClassLoadingException; 022import ch.qos.logback.core.util.IncompatibleClassException; 023 024import static ch.qos.logback.core.rolling.helper.CompressionMode.GZ_SUFFIX; 025import static ch.qos.logback.core.rolling.helper.CompressionMode.XZ_SUFFIX; 026import static ch.qos.logback.core.rolling.helper.CompressionMode.ZIP_SUFFIX; 027import static ch.qos.logback.core.util.OptionHelper.instantiateByClassName; 028 029/** 030 * The <code>Compression</code> class implements ZIP and GZ file 031 * compression/decompression methods. 032 * 033 * @author Ceki Gülcü 034 */ 035public class Compressor extends ContextAwareBase { 036 037 public static final String COULD_NOT_OBTAIN_COMPRESSION_STRATEGY_MESSAGE = "Could not obtain compression strategy"; 038 public static final String XZ_COMPRESSION_STRATEGY_CLASS_NAME = "ch.qos.logback.core.rolling.helper.XZCompressionStrategy"; 039 040 final CompressionMode compressionMode; 041 042 static final int BUFFER_SIZE = 8192; 043 044 public Compressor(CompressionMode compressionMode) { 045 this.compressionMode = compressionMode; 046 } 047 048 /** 049 * @param originalFileName 050 * @param compressedFileName 051 * @param innerEntryName The name of the file within the zip file. Use for 052 * ZIP compression. 053 */ 054 public void compress(String originalFileName, String compressedFileName, String innerEntryName) { 055 CompressionStrategy compressionStrategy = makeCompressionStrategy(compressionMode); 056 if (compressionStrategy == null) { 057 addWarn(COULD_NOT_OBTAIN_COMPRESSION_STRATEGY_MESSAGE); 058 return; 059 } 060 compressionStrategy.setContext(getContext()); 061 compressionStrategy.compress(originalFileName, compressedFileName, innerEntryName); 062 } 063 064 CompressionStrategy makeCompressionStrategy(CompressionMode compressionMode) { 065 switch (compressionMode) { 066 case GZ: 067 return new GZCompressionStrategy(); 068 case ZIP: 069 return new ZipCompressionStrategy(); 070 case XZ: 071 return dynamicInstantiation(XZ_COMPRESSION_STRATEGY_CLASS_NAME); 072 case NONE: 073 throw new UnsupportedOperationException("compress method called in NONE compression mode"); 074 default: 075 return null; 076 } 077 } 078 079 private CompressionStrategy dynamicInstantiation(String className) { 080 try { 081 return (CompressionStrategy) instantiateByClassName(className, CompressionStrategy.class, getContext()); 082 } catch (IncompatibleClassException | DynamicClassLoadingException e) { 083 addError("Could not instantiate " + className, e); 084 return null; 085 } 086 } 087 088 static public String computeFileNameStrWithoutCompSuffix(String fileNamePatternStr, CompressionMode compressionMode) { 089 int len = fileNamePatternStr.length(); 090 switch (compressionMode) { 091 case GZ: 092 if (fileNamePatternStr.endsWith(GZ_SUFFIX)) 093 return fileNamePatternStr.substring(0, len - GZ_SUFFIX.length()); 094 else 095 return fileNamePatternStr; 096 case ZIP: 097 if (fileNamePatternStr.endsWith(ZIP_SUFFIX)) 098 return fileNamePatternStr.substring(0, len - ZIP_SUFFIX.length()); 099 else 100 return fileNamePatternStr; 101 case XZ: 102 if (fileNamePatternStr.endsWith(XZ_SUFFIX)) 103 return fileNamePatternStr.substring(0, len - XZ_SUFFIX.length()); 104 else 105 return fileNamePatternStr; 106 case NONE: 107 return fileNamePatternStr; 108 } 109 throw new IllegalStateException("Execution should not reach this point"); 110 } 111 112 @Override 113 public String toString() { 114 return this.getClass().getName(); 115 } 116 117 public Future<?> asyncCompress(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) throws RolloverFailure { 118 CompressionRunnable runnable = new CompressionRunnable(nameOfFile2Compress, nameOfCompressedFile, innerEntryName); 119 ExecutorService executorService = context.getExecutorService(); 120 Future<?> future = executorService.submit(runnable); 121 return future; 122 } 123 124 class CompressionRunnable implements Runnable { 125 final String nameOfFile2Compress; 126 final String nameOfCompressedFile; 127 final String innerEntryName; 128 129 public CompressionRunnable(String nameOfFile2Compress, String nameOfCompressedFile, String innerEntryName) { 130 this.nameOfFile2Compress = nameOfFile2Compress; 131 this.nameOfCompressedFile = nameOfCompressedFile; 132 this.innerEntryName = innerEntryName; 133 } 134 135 public void run() { 136 137 Compressor.this.compress(nameOfFile2Compress, nameOfCompressedFile, innerEntryName); 138 } 139 } 140 141}