1 package eu.fbk.knowledgestore.filestore;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.OutputStream;
6 import java.util.zip.Deflater;
7 import java.util.zip.GZIPInputStream;
8 import java.util.zip.GZIPOutputStream;
9
10 import javax.annotation.Nullable;
11
12 import com.google.common.base.Function;
13 import com.google.common.base.MoreObjects;
14 import com.google.common.base.Preconditions;
15
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 import eu.fbk.knowledgestore.data.Data;
20 import eu.fbk.knowledgestore.data.Stream;
21
22
23
24
25
26
27
28
29
30
31
32
33 public final class GzippedFileStore extends ForwardingFileStore {
34
35 private static final Logger LOGGER = LoggerFactory.getLogger(GzippedFileStore.class);
36
37 private static final int DEFAULT_COMPRESSION_LEVEL = Deflater.DEFAULT_COMPRESSION;
38
39 private static final int DEFAULT_BUFFER_SIZE = 512;
40
41 private static final boolean DEFAULT_FORCE_COMPRESSION = true;
42
43 private final FileStore delegate;
44
45 private final int compressionLevel;
46
47 private final int bufferSize;
48
49 private final boolean forceCompression;
50
51
52
53
54
55
56
57
58
59 public GzippedFileStore(final FileStore delegate) {
60 this(delegate, null, null, null);
61 }
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public GzippedFileStore(final FileStore delegate, @Nullable final Integer compressionLevel,
81 @Nullable final Integer bufferSize, @Nullable final Boolean forceCompression) {
82
83 Preconditions.checkNotNull(delegate);
84 Preconditions.checkArgument(compressionLevel == null
85 || compressionLevel == Deflater.DEFAULT_COMPRESSION
86 || compressionLevel >= Deflater.BEST_SPEED
87 && compressionLevel <= Deflater.BEST_COMPRESSION);
88 Preconditions.checkArgument(bufferSize > 0);
89
90 this.delegate = Preconditions.checkNotNull(delegate);
91 this.compressionLevel = MoreObjects.firstNonNull(compressionLevel,
92 DEFAULT_COMPRESSION_LEVEL);
93 this.bufferSize = MoreObjects.firstNonNull(bufferSize, DEFAULT_BUFFER_SIZE);
94 this.forceCompression = MoreObjects.firstNonNull(forceCompression,
95 DEFAULT_FORCE_COMPRESSION);
96
97 LOGGER.info("GZippedFileStore configured, compression={}, buffer={}", compressionLevel,
98 bufferSize);
99 }
100
101 @Override
102 protected FileStore delegate() {
103 return this.delegate;
104 }
105
106 @Override
107 public InputStream read(final String filename) throws FileMissingException, IOException {
108 final String internalFilename = toInternalFilename(filename);
109 if (internalFilename.equals(filename)) {
110 return super.read(filename);
111 } else {
112 return new GZIPInputStream(super.read(internalFilename), this.bufferSize);
113 }
114 }
115
116 @Override
117 public OutputStream write(final String filename) throws FileExistsException, IOException {
118 final String internalFilename = toInternalFilename(filename);
119 if (internalFilename.equals(filename)) {
120 return super.write(filename);
121 } else {
122 return new GZIPOutputStream(super.write(internalFilename), this.bufferSize) {
123
124 {
125 this.def.setLevel(GzippedFileStore.this.compressionLevel);
126 }
127
128 };
129 }
130 }
131
132 @Override
133 public void delete(final String filename) throws FileMissingException, IOException {
134 super.delete(toInternalFilename(filename));
135 }
136
137 @Override
138 public Stream<String> list() throws IOException {
139 return super.list().transform(new Function<String, String>() {
140
141 @Override
142 public String apply(final String filename) {
143 return toExternalFilename(filename);
144 }
145
146 }, 0);
147 }
148
149 private String toInternalFilename(final String filename) {
150 return this.forceCompression || Data.isMimeTypeCompressible(
151 Data.extensionToMimeType(filename)) ? filename + ".gz" : filename;
152 }
153
154 private String toExternalFilename(final String filename) {
155 return filename.endsWith(".gz") ? filename.substring(0, filename.length() - 3) : filename;
156 }
157
158 }