1 package nom.tam.fits.compression.provider;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 import java.lang.reflect.Constructor;
35 import java.lang.reflect.InvocationTargetException;
36 import java.nio.Buffer;
37 import java.nio.ByteBuffer;
38 import java.util.ServiceLoader;
39 import java.util.logging.Level;
40 import java.util.logging.Logger;
41
42 import nom.tam.fits.FitsException;
43 import nom.tam.fits.compression.algorithm.api.ICompressOption;
44 import nom.tam.fits.compression.algorithm.api.ICompressor;
45 import nom.tam.fits.compression.algorithm.api.ICompressorControl;
46 import nom.tam.fits.compression.algorithm.gzip.GZipCompressor.ByteGZipCompressor;
47 import nom.tam.fits.compression.algorithm.gzip.GZipCompressor.DoubleGZipCompressor;
48 import nom.tam.fits.compression.algorithm.gzip.GZipCompressor.FloatGZipCompressor;
49 import nom.tam.fits.compression.algorithm.gzip.GZipCompressor.IntGZipCompressor;
50 import nom.tam.fits.compression.algorithm.gzip.GZipCompressor.LongGZipCompressor;
51 import nom.tam.fits.compression.algorithm.gzip.GZipCompressor.ShortGZipCompressor;
52 import nom.tam.fits.compression.algorithm.gzip2.GZip2Compressor.ByteGZip2Compressor;
53 import nom.tam.fits.compression.algorithm.gzip2.GZip2Compressor.DoubleGZip2Compressor;
54 import nom.tam.fits.compression.algorithm.gzip2.GZip2Compressor.FloatGZip2Compressor;
55 import nom.tam.fits.compression.algorithm.gzip2.GZip2Compressor.IntGZip2Compressor;
56 import nom.tam.fits.compression.algorithm.gzip2.GZip2Compressor.LongGZip2Compressor;
57 import nom.tam.fits.compression.algorithm.gzip2.GZip2Compressor.ShortGZip2Compressor;
58 import nom.tam.fits.compression.algorithm.hcompress.HCompressor.ByteHCompressor;
59 import nom.tam.fits.compression.algorithm.hcompress.HCompressor.DoubleHCompressor;
60 import nom.tam.fits.compression.algorithm.hcompress.HCompressor.FloatHCompressor;
61 import nom.tam.fits.compression.algorithm.hcompress.HCompressor.IntHCompressor;
62 import nom.tam.fits.compression.algorithm.hcompress.HCompressor.ShortHCompressor;
63 import nom.tam.fits.compression.algorithm.hcompress.HCompressorQuantizeOption;
64 import nom.tam.fits.compression.algorithm.plio.PLIOCompress.BytePLIOCompressor;
65 import nom.tam.fits.compression.algorithm.plio.PLIOCompress.IntPLIOCompressor;
66 import nom.tam.fits.compression.algorithm.plio.PLIOCompress.ShortPLIOCompressor;
67 import nom.tam.fits.compression.algorithm.quant.QuantizeOption;
68 import nom.tam.fits.compression.algorithm.quant.QuantizeProcessor.DoubleQuantCompressor;
69 import nom.tam.fits.compression.algorithm.quant.QuantizeProcessor.FloatQuantCompressor;
70 import nom.tam.fits.compression.algorithm.rice.RiceCompressor.ByteRiceCompressor;
71 import nom.tam.fits.compression.algorithm.rice.RiceCompressor.DoubleRiceCompressor;
72 import nom.tam.fits.compression.algorithm.rice.RiceCompressor.FloatRiceCompressor;
73 import nom.tam.fits.compression.algorithm.rice.RiceCompressor.IntRiceCompressor;
74 import nom.tam.fits.compression.algorithm.rice.RiceCompressor.ShortRiceCompressor;
75 import nom.tam.fits.compression.algorithm.rice.RiceQuantizeCompressOption;
76 import nom.tam.fits.compression.algorithm.uncompressed.NoCompressCompressor.ByteNoCompressCompressor;
77 import nom.tam.fits.compression.algorithm.uncompressed.NoCompressCompressor.DoubleNoCompressCompressor;
78 import nom.tam.fits.compression.algorithm.uncompressed.NoCompressCompressor.FloatNoCompressCompressor;
79 import nom.tam.fits.compression.algorithm.uncompressed.NoCompressCompressor.IntNoCompressCompressor;
80 import nom.tam.fits.compression.algorithm.uncompressed.NoCompressCompressor.LongNoCompressCompressor;
81 import nom.tam.fits.compression.algorithm.uncompressed.NoCompressCompressor.ShortNoCompressCompressor;
82 import nom.tam.fits.compression.provider.api.ICompressorProvider;
83 import nom.tam.fits.compression.provider.param.api.ICompressHeaderParameter;
84 import nom.tam.fits.compression.provider.param.api.ICompressParameters;
85 import nom.tam.fits.compression.provider.param.base.CompressParameters;
86 import nom.tam.fits.compression.provider.param.hcompress.HCompressParameters;
87 import nom.tam.fits.compression.provider.param.rice.RiceCompressParameters;
88
89
90
91
92 @SuppressWarnings({"javadoc", "deprecation"})
93 public class CompressorProvider implements ICompressorProvider {
94
95
96
97
98
99 protected static class TileCompressorControl implements ICompressorControl {
100
101 private final Constructor<ICompressor<Buffer>>[] constructors;
102
103 private Class<? extends ICompressOption> optionClass;
104
105 private Class<?> quantType;
106
107 @SuppressWarnings("unchecked")
108 protected TileCompressorControl(Class<?> compressorClass) {
109 constructors = (Constructor<ICompressor<Buffer>>[]) compressorClass.getConstructors();
110 for (Constructor<ICompressor<Buffer>> c : constructors) {
111 if (c.getParameterTypes().length == 1) {
112 optionClass = (Class<? extends ICompressOption>) c.getParameterTypes()[0];
113 break;
114 }
115 }
116 }
117
118
119
120
121
122
123
124
125
126
127
128 protected TileCompressorControl setQuantType(Class<?> floatingPointType) {
129 quantType = floatingPointType;
130 return this;
131 }
132
133 @Override
134 public boolean compress(Buffer in, ByteBuffer out, ICompressOption option) {
135 try {
136 return newCompressor(option).compress(in, out);
137 } catch (Exception e) {
138 LOG.log(Level.FINE, "could not compress using " + constructors[0].getName()
139 + " must fallback to other compression method", e);
140 return false;
141 }
142 }
143
144 @Override
145 public void decompress(ByteBuffer in, Buffer out, ICompressOption option) {
146 try {
147 newCompressor(option).decompress(in, out);
148 } catch (Exception e) {
149 throw new IllegalStateException("could not decompress " + constructors[0].getName(), e);
150 }
151 }
152
153 @Override
154 public ICompressOption option() {
155 ICompressOption option = null;
156 if (optionClass != null) {
157 try {
158 option = optionClass.getDeclaredConstructor().newInstance();
159 } catch (Exception e) {
160 throw new IllegalStateException("could not instantiate option class for " + constructors[0].getName(),
161 e);
162 }
163 }
164
165 if (option == null) {
166 option = NULL_OPTION;
167 }
168
169 if (quantType != null) {
170 return new QuantizeOption(option);
171 }
172
173 return option;
174 }
175
176 @SuppressWarnings({"unchecked", "rawtypes"})
177 private ICompressor<Buffer> newCompressor(ICompressOption option)
178 throws FitsException, InstantiationException, IllegalAccessException, InvocationTargetException {
179 ICompressor<Buffer> compressor = null;
180 QuantizeOption quantOption = null;
181
182 if (option instanceof QuantizeOption) {
183 quantOption = (QuantizeOption) option;
184 option = quantOption.getCompressOption();
185 }
186
187 if (option == NULL_OPTION) {
188 option = null;
189 }
190
191 for (Constructor<ICompressor<Buffer>> c : constructors) {
192 Class<?>[] parms = c.getParameterTypes();
193
194 if (parms.length == 0 && option == null) {
195
196 compressor = c.newInstance();
197 break;
198 }
199
200 if (parms.length == 1 && option != null) {
201
202 Class<? extends ICompressOption> p = (Class<? extends ICompressOption>) parms[0];
203 if (quantOption != null && p.isAssignableFrom(quantOption.getClass())) {
204 compressor = c.newInstance(quantOption);
205 quantOption = null;
206 break;
207 }
208 if (p.isAssignableFrom(option.getClass())) {
209 compressor = c.newInstance(option);
210 break;
211 }
212 }
213 }
214
215 if (compressor == null) {
216 throw new FitsException("Could not instantiate (de)compressor for the specified options");
217 }
218
219 if (quantOption != null && quantType != null) {
220 if (quantType.equals(double.class)) {
221 return (ICompressor) new DoubleQuantCompressor(quantOption, (ICompressor) compressor);
222 }
223 if (quantType.equals(float.class)) {
224 return (ICompressor) new FloatQuantCompressor(quantOption, (ICompressor) compressor);
225 }
226 }
227
228 return compressor;
229 }
230 }
231
232 private static final ICompressOption NULL_OPTION = new ICompressOption() {
233
234 @Override
235 public ICompressOption copy() {
236 return this;
237 }
238
239 @Override
240 public ICompressParameters getCompressionParameters() {
241 return NULL_PARAMETERS;
242 }
243
244 @Override
245 public boolean isLossyCompression() {
246 return false;
247 }
248
249 @Override
250 public void setParameters(ICompressParameters parameters) {
251 }
252
253 @Override
254 public ICompressOption setTileHeight(int value) {
255 return this;
256 }
257
258 @Override
259 public ICompressOption setTileWidth(int value) {
260 return this;
261 }
262
263 @Override
264 public <T> T unwrap(Class<T> clazz) {
265 return clazz.isAssignableFrom(this.getClass()) ? clazz.cast(this) : null;
266 }
267 };
268
269 private static final ICompressParameters NULL_PARAMETERS = new CompressParameters() {
270
271 @Override
272 protected ICompressHeaderParameter[] headerParameters() {
273 return new ICompressHeaderParameter[0];
274 }
275
276 @Override
277 public ICompressParameters copy(ICompressOption option) {
278 return this;
279 }
280 };
281
282
283 private static final Class<?>[][] AVAILABLE_COMPRESSORS = {
284 {ByteRiceCompressor.class, RiceCompressParameters.class},
285 {ShortRiceCompressor.class, RiceCompressParameters.class},
286 {IntRiceCompressor.class, RiceCompressParameters.class},
287 {FloatRiceCompressor.class, RiceQuantizeCompressOption.class},
288 {DoubleRiceCompressor.class, RiceQuantizeCompressOption.class},
289 {BytePLIOCompressor.class},
290 {ShortPLIOCompressor.class},
291 {IntPLIOCompressor.class},
292 {ByteHCompressor.class, HCompressParameters.class},
293 {ShortHCompressor.class, HCompressParameters.class},
294 {IntHCompressor.class, HCompressParameters.class},
295 {FloatHCompressor.class, HCompressorQuantizeOption.class},
296 {DoubleHCompressor.class, HCompressorQuantizeOption.class},
297 {ByteGZip2Compressor.class},
298 {ShortGZip2Compressor.class},
299 {IntGZip2Compressor.class},
300 {FloatGZip2Compressor.class},
301 {DoubleGZip2Compressor.class},
302 {LongGZip2Compressor.class},
303 {ByteGZipCompressor.class},
304 {ShortGZipCompressor.class},
305 {IntGZipCompressor.class},
306 {LongGZipCompressor.class},
307 {FloatGZipCompressor.class},
308 {DoubleGZipCompressor.class},
309 {ByteNoCompressCompressor.class},
310 {ShortNoCompressCompressor.class},
311 {IntNoCompressCompressor.class},
312 {LongNoCompressCompressor.class},
313 {FloatNoCompressCompressor.class},
314 {DoubleNoCompressCompressor.class}};
315
316
317 private static final CompressorControlNameComputer NAME_COMPUTER = new CompressorControlNameComputer();
318
319
320
321
322 private static final Logger LOG = Logger.getLogger(CompressorProvider.class.getName());
323
324 public static ICompressorControl findCompressorControl(String quantAlgorithm, String compressionAlgorithm,
325 Class<?> baseType) {
326 for (ICompressorProvider iTileCompressorProvider : ServiceLoader.load(ICompressorProvider.class,
327 Thread.currentThread().getContextClassLoader())) {
328 ICompressorControl result = iTileCompressorProvider.createCompressorControl(quantAlgorithm,
329 compressionAlgorithm, baseType);
330 if (result != null) {
331 return result;
332 }
333 }
334 return new CompressorProvider().createCompressorControl(quantAlgorithm, compressionAlgorithm, baseType);
335 }
336
337 @Override
338 public ICompressorControl createCompressorControl(String quantAlgorithm, String compressionAlgorithm,
339 Class<?> baseType) {
340 Class<?> quantType = null;
341
342 if (quantAlgorithm != null) {
343
344 if (baseType.equals(double.class) || baseType.equals(float.class)) {
345 quantType = baseType;
346 baseType = int.class;
347 quantAlgorithm = null;
348 }
349 }
350
351 String className = NAME_COMPUTER.createCompressorClassName(quantAlgorithm, compressionAlgorithm, baseType);
352
353 for (Class<?>[] types : AVAILABLE_COMPRESSORS) {
354 Class<?> compressorClass = types[0];
355 if (compressorClass.getSimpleName().equals(className)) {
356 TileCompressorControl tc = new TileCompressorControl(compressorClass);
357 tc.setQuantType(quantType);
358 return tc;
359 }
360 }
361
362 return null;
363 }
364 }