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