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 try {
192 for (Constructor<ICompressor<Buffer>> c : constructors) {
193 Class<?>[] parms = c.getParameterTypes();
194
195 if (parms.length == 0 && option == null) {
196
197 compressor = c.newInstance();
198 break;
199 }
200
201 if (parms.length == 1 && option != null) {
202
203 Class<? extends ICompressOption> p = (Class<? extends ICompressOption>) parms[0];
204 if (quantOption != null && p.isAssignableFrom(quantOption.getClass())) {
205 compressor = c.newInstance(quantOption);
206 quantOption = null;
207 break;
208 }
209 if (p.isAssignableFrom(option.getClass())) {
210 compressor = c.newInstance(option);
211 break;
212 }
213 }
214
215 }
216
217 if (compressor == null) {
218 throw new FitsException("Could not instantiate (de)compressor for the specified options");
219 }
220
221 if (quantOption != null && quantType != null) {
222 if (quantType.equals(double.class)) {
223 return (ICompressor) new DoubleQuantCompressor(quantOption, (ICompressor) compressor);
224 }
225 if (quantType.equals(float.class)) {
226 return (ICompressor) new FloatQuantCompressor(quantOption, (ICompressor) compressor);
227 }
228 }
229
230 return compressor;
231 } catch (Exception e) {
232 e.printStackTrace();
233 }
234
235 return null;
236 }
237 }
238
239 private static final ICompressOption NULL_OPTION = new ICompressOption() {
240
241 @Override
242 public ICompressOption copy() {
243 return this;
244 }
245
246 @Override
247 public ICompressParameters getCompressionParameters() {
248 return NULL_PARAMETERS;
249 }
250
251 @Override
252 public boolean isLossyCompression() {
253 return false;
254 }
255
256 @Override
257 public void setParameters(ICompressParameters parameters) {
258 }
259
260 @Override
261 public ICompressOption setTileHeight(int value) {
262 return this;
263 }
264
265 @Override
266 public ICompressOption setTileWidth(int value) {
267 return this;
268 }
269
270 @Override
271 public <T> T unwrap(Class<T> clazz) {
272 return clazz.isAssignableFrom(this.getClass()) ? clazz.cast(this) : null;
273 }
274 };
275
276 private static final ICompressParameters NULL_PARAMETERS = new CompressParameters() {
277
278 @Override
279 protected ICompressHeaderParameter[] headerParameters() {
280 return new ICompressHeaderParameter[0];
281 }
282
283 @Override
284 public ICompressParameters copy(ICompressOption option) {
285 return this;
286 }
287 };
288
289
290 private static final Class<?>[][] AVAILABLE_COMPRESSORS = {
291 {ByteRiceCompressor.class, RiceCompressParameters.class},
292 {ShortRiceCompressor.class, RiceCompressParameters.class},
293 {IntRiceCompressor.class, RiceCompressParameters.class},
294 {FloatRiceCompressor.class, RiceQuantizeCompressOption.class},
295 {DoubleRiceCompressor.class, RiceQuantizeCompressOption.class},
296 {BytePLIOCompressor.class},
297 {ShortPLIOCompressor.class},
298 {IntPLIOCompressor.class},
299 {ByteHCompressor.class, HCompressParameters.class},
300 {ShortHCompressor.class, HCompressParameters.class},
301 {IntHCompressor.class, HCompressParameters.class},
302 {FloatHCompressor.class, HCompressorQuantizeOption.class},
303 {DoubleHCompressor.class, HCompressorQuantizeOption.class},
304 {ByteGZip2Compressor.class},
305 {ShortGZip2Compressor.class},
306 {IntGZip2Compressor.class},
307 {FloatGZip2Compressor.class},
308 {DoubleGZip2Compressor.class},
309 {LongGZip2Compressor.class},
310 {ByteGZipCompressor.class},
311 {ShortGZipCompressor.class},
312 {IntGZipCompressor.class},
313 {LongGZipCompressor.class},
314 {FloatGZipCompressor.class},
315 {DoubleGZipCompressor.class},
316 {ByteNoCompressCompressor.class},
317 {ShortNoCompressCompressor.class},
318 {IntNoCompressCompressor.class},
319 {LongNoCompressCompressor.class},
320 {FloatNoCompressCompressor.class},
321 {DoubleNoCompressCompressor.class}};
322
323
324 private static final CompressorControlNameComputer NAME_COMPUTER = new CompressorControlNameComputer();
325
326
327
328
329 private static final Logger LOG = Logger.getLogger(CompressorProvider.class.getName());
330
331 public static ICompressorControl findCompressorControl(String quantAlgorithm, String compressionAlgorithm,
332 Class<?> baseType) {
333 for (ICompressorProvider iTileCompressorProvider : ServiceLoader.load(ICompressorProvider.class,
334 Thread.currentThread().getContextClassLoader())) {
335 ICompressorControl result = iTileCompressorProvider.createCompressorControl(quantAlgorithm,
336 compressionAlgorithm, baseType);
337 if (result != null) {
338 return result;
339 }
340 }
341 return new CompressorProvider().createCompressorControl(quantAlgorithm, compressionAlgorithm, baseType);
342 }
343
344 @Override
345 public ICompressorControl createCompressorControl(String quantAlgorithm, String compressionAlgorithm,
346 Class<?> baseType) {
347 Class<?> quantType = null;
348
349 if (quantAlgorithm != null) {
350
351 if (baseType.equals(double.class) || baseType.equals(float.class)) {
352 quantType = baseType;
353 baseType = int.class;
354 quantAlgorithm = null;
355 }
356 }
357
358 String className = NAME_COMPUTER.createCompressorClassName(quantAlgorithm, compressionAlgorithm, baseType);
359
360 for (Class<?>[] types : AVAILABLE_COMPRESSORS) {
361 Class<?> compressorClass = types[0];
362 if (compressorClass.getSimpleName().equals(className)) {
363 TileCompressorControl tc = new TileCompressorControl(compressorClass);
364 tc.setQuantType(quantType);
365 return tc;
366 }
367 }
368
369 return null;
370 }
371 }