001/*****************************************************************************
002 * Copyright by The HDF Group.                                               *
003 * Copyright by the Board of Trustees of the University of Illinois.         *
004 * All rights reserved.                                                      *
005 *                                                                           *
006 * This file is part of the HDF Java Products distribution.                  *
007 * The full copyright notice, including terms governing use, modification,   *
008 * and redistribution, is contained in the files COPYING and Copyright.html. *
009 * COPYING can be found at the root of the source code distribution tree.    *
010 * Or, see https://support.hdfgroup.org/products/licenses.html               *
011 * If you do not have access to either file, you may request a copy from     *
012 * help@hdfgroup.org.                                                        *
013 ****************************************************************************/
014
015package hdf.view.TableView;
016
017import java.math.BigInteger;
018import java.util.HashMap;
019import java.util.List;
020import java.util.StringTokenizer;
021
022import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
023import org.eclipse.nebula.widgets.nattable.data.validate.DataValidator;
024import org.eclipse.nebula.widgets.nattable.data.validate.ValidationFailedException;
025import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
026
027import hdf.hdf5lib.HDF5Constants;
028import hdf.object.CompoundDataFormat;
029import hdf.object.DataFormat;
030import hdf.object.Datatype;
031import hdf.object.h5.H5Datatype;
032
033/**
034 * A Factory class to return a DataValidator class for a NatTable instance based
035 * upon the Datatype that it is supplied.
036 *
037 * @author Jordan T. Henderson
038 * @version 1.0 6/28/2018
039 *
040 */
041public class DataValidatorFactory {
042
043    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DataValidatorFactory.class);
044
045    /*
046     * To keep things clean from an API perspective, keep a static reference to the
047     * last CompoundDataFormat that was passed in. This keeps us from needing to
048     * pass the CompoundDataFormat object as a parameter to every DataValidator
049     * class, since it's really only needed by the CompoundDataValidator.
050     */
051    private static DataFormat dataFormatReference = null;
052
053    public static HDFDataValidator getDataValidator(final DataFormat dataObject) throws Exception {
054        if (dataObject == null) {
055            log.debug("getDataValidator(DataFormat): data object is null");
056            throw new Exception("Must supply a valid DataFormat to the DataValidatorFactory");
057        }
058
059        dataFormatReference = dataObject;
060
061        HDFDataValidator validator = null;
062        try {
063            validator = getDataValidator(dataObject.getDatatype());
064        }
065        catch (Exception ex) {
066            log.debug("getDataValidator(DataFormat): failed to retrieve a DataValidator: ", ex);
067            validator = null;
068        }
069
070        /*
071         * By default, never validate if a proper DataValidator was not found.
072         */
073        if (validator == null) {
074            log.debug("getDataValidator(DataFormat): using a default data validator");
075
076            validator = new HDFDataValidator(dataObject.getDatatype());
077        }
078
079        return validator;
080    }
081
082    private static HDFDataValidator getDataValidator(Datatype dtype) throws Exception {
083        HDFDataValidator validator = null;
084
085        try {
086            if (dtype.isCompound())
087                validator = new CompoundDataValidator(dtype);
088            else if (dtype.isArray())
089                validator = new ArrayDataValidator(dtype);
090            else if (dtype.isVLEN() && !dtype.isVarStr())
091                validator = new VlenDataValidator(dtype);
092            else if (dtype.isString() || dtype.isVarStr())
093                validator = new StringDataValidator(dtype);
094            else if (dtype.isChar())
095                validator = new CharDataValidator(dtype);
096            else if (dtype.isInteger() || dtype.isFloat())
097                validator = new NumericalDataValidator(dtype);
098            else if (dtype.isEnum())
099                validator = new EnumDataValidator(dtype);
100            else if (dtype.isOpaque() || dtype.isBitField())
101                validator = new BitfieldDataValidator(dtype);
102            else if (dtype.isRef())
103                validator = new RefDataValidator(dtype);
104        }
105        catch (Exception ex) {
106            log.debug("getDataValidator(Datatype): failed to retrieve a DataValidator: ", ex);
107            validator = null;
108        }
109
110        /*
111         * By default, never validate if a proper DataValidator was not found.
112         */
113        if (validator == null) {
114            log.debug("getDataValidator(Datatype): using a default data validator");
115
116            validator = new HDFDataValidator(dtype);
117        }
118
119        return validator;
120    }
121
122    public static class HDFDataValidator extends DataValidator {
123        protected org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(HDFDataValidator.class);
124
125        /*
126         * This field is only used for CompoundDataValidator, but when the top-level
127         * DataValidator is a "container" type, such as an ArrayDataValidator, we have
128         * to set this field and pass it through in case there is a
129         * CompoundDataValidator at the bottom of the chain.
130         */
131        protected int cellColIdx;
132
133        HDFDataValidator(final Datatype dtype) {
134            cellColIdx = -1;
135        }
136
137        @Override
138        public boolean validate(int colIndex, int rowIndex, Object newValue) {
139            throwValidationFailedException(rowIndex, colIndex, newValue,
140                    "A proper DataValidator wasn't found for this type of data. Writing this type of data will be disabled.");
141
142            return false;
143        }
144
145        protected void checkValidValue(Object newValue) throws ValidationFailedException {
146            if (newValue == null)
147                throw new ValidationFailedException("value is null");
148
149            if (!(newValue instanceof String))
150                throw new ValidationFailedException("value is not a String");
151        }
152
153        protected void throwValidationFailedException(int rowIndex, int colIndex, Object newValue, String reason)
154                throws ValidationFailedException {
155            throw new ValidationFailedException("Failed to update value at " + "(" + rowIndex + ", "
156                    + colIndex + ") to '" + newValue.toString() + "': " + reason);
157        }
158    }
159
160    /*
161     * NatTable DataValidator to validate entered input for a dataset with
162     * a Compound datatype by calling the appropriate validator on the member
163     * at the given row and column index. The correct validator is determined
164     * by taking the column index modulo the number of selected members in the
165     * Compound datatype, and grabbing the correct validator from the stored
166     * list of validators.
167     */
168    private static class CompoundDataValidator extends HDFDataValidator {
169        private final HashMap<Integer, Integer> baseValidatorIndexMap;
170        private final HashMap<Integer, Integer> relCmpdStartIndexMap;
171        private final HDFDataValidator[]        memberValidators;
172        private final int                       nTotFields;
173
174        CompoundDataValidator(final Datatype dtype) throws Exception {
175            super(dtype);
176
177            log = org.slf4j.LoggerFactory.getLogger(CompoundDataValidator.class);
178
179            if (!dtype.isCompound()) {
180                log.debug("datatype is not a compound type");
181                throw new Exception("CompoundDataValidator: datatype is not a compound type");
182            }
183
184            CompoundDataFormat compoundFormat = (CompoundDataFormat) dataFormatReference;
185
186            List<Datatype> localSelectedTypes = DataFactoryUtils.filterNonSelectedMembers(compoundFormat, dtype);
187
188            log.trace("setting up {} base HDFDataValidators", localSelectedTypes.size());
189
190            memberValidators = new HDFDataValidator[localSelectedTypes.size()];
191            for (int i = 0; i < memberValidators.length; i++) {
192                log.trace("retrieving DataValidator for member {}", i);
193
194                try {
195                    memberValidators[i] = getDataValidator(localSelectedTypes.get(i));
196                }
197                catch (Exception ex) {
198                    log.debug("failed to retrieve DataValidator for member {}: ", i, ex);
199                    memberValidators[i] = null;
200                }
201            }
202
203            /*
204             * Build necessary index maps.
205             */
206            HashMap<Integer, Integer>[] maps = DataFactoryUtils.buildIndexMaps(compoundFormat, localSelectedTypes);
207            baseValidatorIndexMap = maps[DataFactoryUtils.COL_TO_BASE_CLASS_MAP_INDEX];
208            relCmpdStartIndexMap = maps[DataFactoryUtils.CMPD_START_IDX_MAP_INDEX];
209
210            log.trace("index maps built: baseValidatorIndexMap = {}, relColIdxMap = {}",
211                    baseValidatorIndexMap.toString(), relCmpdStartIndexMap.toString());
212
213            if (baseValidatorIndexMap.size() == 0) {
214                log.debug("base DataValidator index mapping is invalid - size 0");
215                throw new Exception("CompoundDataValidator: invalid DataValidator mapping of size 0 built");
216            }
217
218            if (relCmpdStartIndexMap.size() == 0) {
219                log.debug("compound field start index mapping is invalid - size 0");
220                throw new Exception("CompoundDataValidator: invalid compound field start index mapping of size 0 built");
221            }
222
223            nTotFields = baseValidatorIndexMap.size();
224        }
225
226        @Override
227        public boolean validate(ILayerCell cell, IConfigRegistry configRegistry, Object newValue) {
228            cellColIdx = cell.getColumnIndex() % nTotFields;
229            return validate(cell.getColumnIndex(), cell.getRowIndex(), newValue);
230        }
231
232        @Override
233        public boolean validate(int colIndex, int rowIndex, Object newValue) {
234            log.trace("validate({}, {}, {}): start", rowIndex, colIndex, newValue);
235
236            try {
237                super.checkValidValue(newValue);
238
239                if (cellColIdx >= nTotFields)
240                    cellColIdx %= nTotFields;
241
242                HDFDataValidator validator = memberValidators[baseValidatorIndexMap.get(cellColIdx)];
243                validator.cellColIdx = cellColIdx - relCmpdStartIndexMap.get(cellColIdx);
244
245                validator.validate(colIndex, rowIndex, newValue);
246            }
247            catch (Exception ex) {
248                log.debug("validate({}, {}, {}): failed to validate: ", rowIndex, colIndex, newValue, ex);
249                throw new ValidationFailedException(ex.getMessage(), ex);
250            }
251            finally {
252                log.trace("validate({}, {}, {}): finish", rowIndex, colIndex, newValue);
253            }
254
255            return true;
256        }
257    }
258
259    /*
260     * NatTable DataValidator to validate entered input for a dataset with
261     * an ARRAY datatype by calling the appropriate validator (as determined
262     * by the supplied datatype) on each of the array's elements.
263     */
264    private static class ArrayDataValidator extends HDFDataValidator {
265        private final HDFDataValidator baseValidator;
266
267        ArrayDataValidator(final Datatype dtype) throws Exception {
268            super(dtype);
269
270            log = org.slf4j.LoggerFactory.getLogger(ArrayDataValidator.class);
271
272            if (!dtype.isArray()) {
273                log.debug("datatype is not an array type");
274                throw new Exception("ArrayDataValidator: datatype is not an array type");
275            }
276
277            Datatype baseType = dtype.getDatatypeBase();
278            if (baseType == null) {
279                log.debug("base datatype is null");
280                throw new Exception("ArrayDataValidator: base datatype is null");
281            }
282
283            log.trace("ArrayDataValidator: base Datatype is {}", baseType.getDescription());
284
285            try {
286                baseValidator = getDataValidator(baseType);
287            }
288            catch (Exception ex) {
289                log.debug("couldn't get DataValidator for base datatype: ", ex);
290                throw new Exception("ArrayDataValidator: couldn't get DataValidator for base datatype: " + ex.getMessage());
291            }
292        }
293
294        @Override
295        public boolean validate(ILayerCell cell, IConfigRegistry configRegistry, Object newValue) {
296            cellColIdx = cell.getColumnIndex();
297            return validate(cell.getColumnIndex(), cell.getRowIndex(), newValue);
298        }
299
300        @Override
301        public boolean validate(int colIndex, int rowIndex, Object newValue) {
302            log.trace("validate({}, {}, {}): start", rowIndex, colIndex, newValue);
303
304            try {
305                super.checkValidValue(newValue);
306
307                baseValidator.cellColIdx = cellColIdx;
308
309                StringTokenizer elementReader = new StringTokenizer((String) newValue, " \t\n\r\f,[]");
310                while (elementReader.hasMoreTokens()) {
311                    String nextToken = elementReader.nextToken();
312                    baseValidator.validate(colIndex, rowIndex, nextToken);
313                }
314            }
315            catch (Exception ex) {
316                log.debug("validate({}, {}, {}): failed to validate: ", rowIndex, colIndex, newValue, ex);
317                throw new ValidationFailedException(ex.getMessage(), ex);
318            }
319            finally {
320                log.trace("validate({}, {}, {}): finish", rowIndex, colIndex, newValue);
321            }
322
323            return true;
324        }
325    }
326
327    /*
328     * NatTable DataValidator to validate entered input for a dataset with
329     * a variable-length Datatype (note that this DataValidator should not
330     * be used for String Datatypes that are variable-length).
331     */
332    private static class VlenDataValidator extends HDFDataValidator {
333        private final HDFDataValidator baseValidator;
334
335        VlenDataValidator(Datatype dtype) throws Exception {
336            super(dtype);
337
338            log = org.slf4j.LoggerFactory.getLogger(VlenDataValidator.class);
339
340            if (!dtype.isVLEN() || dtype.isVarStr()) {
341                log.debug("datatype is not a variable-length type or is a variable-length string type (use StringDataValidator)");
342                throw new Exception("VlenDataValidator: datatype is not a variable-length type or is a variable-length string type (use StringDataValidator)");
343            }
344
345            Datatype baseType = dtype.getDatatypeBase();
346            if (baseType == null) {
347                log.debug("base datatype is null");
348                throw new Exception("VlenDataValidator: base datatype is null");
349            }
350
351            log.trace("VlenDataValidator: base Datatype is {}", baseType.getDescription());
352
353            try {
354                baseValidator = getDataValidator(baseType);
355            }
356            catch (Exception ex) {
357                log.debug("couldn't get DataValidator for base datatype: ", ex);
358                throw new Exception("VlenDataValidator: couldn't get DataValidator for base datatype: " + ex.getMessage());
359            }
360        }
361
362        @Override
363        public boolean validate(ILayerCell cell, IConfigRegistry configRegistry, Object newValue) {
364            cellColIdx = cell.getColumnIndex();
365            return validate(cell.getColumnIndex(), cell.getRowIndex(), newValue);
366        }
367
368        @Override
369        public boolean validate(int colIndex, int rowIndex, Object newValue) {
370            log.trace("validate({}, {}, {}): start", rowIndex, colIndex, newValue);
371
372            try {
373                super.checkValidValue(newValue);
374
375                baseValidator.cellColIdx = cellColIdx;
376
377                StringTokenizer elementReader = new StringTokenizer((String) newValue, " \t\n\r\f,()");
378                while (elementReader.hasMoreTokens()) {
379                    String nextToken = elementReader.nextToken();
380                    baseValidator.validate(colIndex, rowIndex, nextToken);
381                }
382            }
383            catch (Exception ex) {
384                log.debug("validate({}, {}, {}): failed to validate: ", rowIndex, colIndex, newValue, ex);
385                throw new ValidationFailedException(ex.getMessage(), ex);
386            }
387            finally {
388                log.trace("validate({}, {}, {}): finish", rowIndex, colIndex, newValue);
389            }
390
391            return true;
392        }
393    }
394
395    /*
396     * NatTable DataValidator to validate entered input for a dataset with a String
397     * Datatype (including Strings of variable-length).
398     */
399    private static class StringDataValidator extends HDFDataValidator {
400        private final Datatype datasetDatatype;
401        private final boolean isH5String;
402
403        StringDataValidator(final Datatype dtype) throws Exception {
404            super(dtype);
405
406            log = org.slf4j.LoggerFactory.getLogger(StringDataValidator.class);
407
408            if (!dtype.isString()) {
409                log.debug("datatype is not a String type");
410                throw new Exception("StringDataValidator: datatype is not a String type");
411            }
412
413            log.trace("StringDataValidator: base Datatype is {}", dtype.getDescription());
414
415            this.datasetDatatype = dtype;
416
417            this.isH5String = (dtype instanceof H5Datatype);
418        }
419
420        @Override
421        public boolean validate(int colIndex, int rowIndex, Object newValue) {
422            log.trace("validate({}, {}, {}): start", rowIndex, colIndex, newValue);
423
424            try {
425                super.checkValidValue(newValue);
426
427                /*
428                 * If this is a fixed-length string type, check to make sure that the data
429                 * length does not exceed the datatype size.
430                 */
431                if (!datasetDatatype.isVarStr()) {
432                    long lenDiff = ((String) newValue).length() - datasetDatatype.getDatatypeSize();
433
434                    if (lenDiff > 0)
435                        throw new Exception("string size larger than datatype size by " + lenDiff
436                            + ((lenDiff > 1) ? " bytes." : " byte."));
437
438                    /*
439                     * TODO: Add Warning about overwriting NULL-terminator character.
440                     */
441                    if (lenDiff == 0 && isH5String) {
442                        H5Datatype h5Type = (H5Datatype) datasetDatatype;
443                        int strPad = h5Type.getNativeStrPad();
444
445                        if (strPad == HDF5Constants.H5T_STR_NULLTERM) {
446
447                        }
448                        else if (strPad == HDF5Constants.H5T_STR_NULLPAD) {
449
450                        }
451                        else if (strPad == HDF5Constants.H5T_STR_SPACEPAD) {
452
453                        }
454                    }
455                }
456            }
457            catch (Exception ex) {
458                log.debug("validate({}, {}, {}): failed to validate: ", rowIndex, colIndex, newValue, ex);
459                super.throwValidationFailedException(rowIndex, colIndex, newValue, ex.getMessage());
460            }
461            finally {
462                log.trace("validate({}, {}, {}): finish", rowIndex, colIndex, newValue);
463            }
464
465            return true;
466        }
467    }
468
469    private static class CharDataValidator extends HDFDataValidator {
470        private final Datatype datasetDatatype;
471
472        CharDataValidator(final Datatype dtype) throws Exception {
473            super(dtype);
474
475            log = org.slf4j.LoggerFactory.getLogger(CharDataValidator.class);
476
477            if (!dtype.isChar()) {
478                log.debug("datatype is not a Character type");
479                throw new Exception("CharDataValidator: datatype is not a Character type");
480            }
481
482            this.datasetDatatype = dtype;
483        }
484
485        @Override
486        public boolean validate(int colIndex, int rowIndex, Object newValue) {
487            log.trace("validate({}, {}, {}): start", rowIndex, colIndex, newValue);
488
489            try {
490                if (datasetDatatype.isUnsigned()) {
491                    /*
492                     * First try to parse as a larger type in order to catch a NumberFormatException
493                     */
494                    Short shortValue = Short.parseShort((String) newValue);
495                    if (shortValue < 0)
496                        throw new NumberFormatException("Invalid negative value for unsigned datatype");
497
498                    if (shortValue > (Byte.MAX_VALUE * 2) + 1)
499                        throw new NumberFormatException("Value out of range. Value:\"" + newValue + "\"");
500                }
501                else {
502                    Byte.parseByte((String) newValue);
503                }
504            }
505            catch (Exception ex) {
506                super.throwValidationFailedException(rowIndex, colIndex, newValue, ex.toString());
507            }
508            finally {
509                log.trace("validate({}, {}, {}): finish", rowIndex, colIndex, newValue);
510            }
511
512            return true;
513        }
514
515    }
516
517    /*
518     * NatTable DataValidator to validate entered input for a dataset with
519     * a numerical Datatype.
520     */
521    private static class NumericalDataValidator extends HDFDataValidator {
522        private final Datatype datasetDatatype;
523
524        NumericalDataValidator(Datatype dtype) throws Exception {
525            super(dtype);
526
527            log = org.slf4j.LoggerFactory.getLogger(NumericalDataValidator.class);
528
529            if (!dtype.isInteger() && !dtype.isFloat()) {
530                log.debug("datatype is not an integer or floating-point type");
531                throw new Exception("NumericalDataValidator: datatype is not an integer or floating-point type");
532            }
533
534            log.trace("NumericalDataValidator: base Datatype is {}", dtype.getDescription());
535
536            this.datasetDatatype = dtype;
537        }
538
539        @Override
540        public boolean validate(int colIndex, int rowIndex, Object newValue) {
541            log.trace("validate({}, {}, {}): start", rowIndex, colIndex, newValue);
542
543            try {
544                super.checkValidValue(newValue);
545
546                switch ((int) datasetDatatype.getDatatypeSize()) {
547                    case 1:
548                        if (datasetDatatype.isUnsigned()) {
549                            /*
550                             * First try to parse as a larger type in order to catch a NumberFormatException
551                             */
552                            Short shortValue = Short.parseShort((String) newValue);
553                            if (shortValue < 0)
554                                throw new NumberFormatException("Invalid negative value for unsigned datatype");
555
556                            if (shortValue > (Byte.MAX_VALUE * 2) + 1)
557                                throw new NumberFormatException("Value out of range. Value:\"" + newValue + "\"");
558                        }
559                        else {
560                            Byte.parseByte((String) newValue);
561                        }
562                        break;
563
564                    case 2:
565                        if (datasetDatatype.isUnsigned()) {
566                            /*
567                             * First try to parse as a larger type in order to catch a NumberFormatException
568                             */
569                            Integer intValue = Integer.parseInt((String) newValue);
570                            if (intValue < 0)
571                                throw new NumberFormatException("Invalid negative value for unsigned datatype");
572
573                            if (intValue > (Short.MAX_VALUE * 2) + 1)
574                                throw new NumberFormatException("Value out of range. Value:\"" + newValue + "\"");
575                        }
576                        else {
577                            Short.parseShort((String) newValue);
578                        }
579                        break;
580
581                    case 4:
582                        if (datasetDatatype.isInteger()) {
583                            if (datasetDatatype.isUnsigned()) {
584                                /*
585                                 * First try to parse as a larger type in order to catch a NumberFormatException
586                                 */
587                                Long longValue = Long.parseLong((String) newValue);
588                                if (longValue < 0)
589                                    throw new NumberFormatException("Invalid negative value for unsigned datatype");
590
591                                if (longValue > ((long) Integer.MAX_VALUE * 2) + 1)
592                                    throw new NumberFormatException("Value out of range. Value:\"" + newValue + "\"");
593                            }
594                            else {
595                                Integer.parseInt((String) newValue);
596                            }
597                        }
598                        else {
599                            /* Floating-point type */
600                            Float.parseFloat((String) newValue);
601                        }
602                        break;
603
604                    case 8:
605                        if (datasetDatatype.isInteger()) {
606                            if (datasetDatatype.isUnsigned()) {
607                                /*
608                                 * First try to parse as a larger type in order to catch a NumberFormatException
609                                 */
610                                BigInteger bigValue = new BigInteger((String) newValue);
611                                if (bigValue.compareTo(BigInteger.ZERO) < 0)
612                                    throw new NumberFormatException("Invalid negative value for unsigned datatype");
613
614                                BigInteger maxRange = BigInteger.valueOf(Long.MAX_VALUE).multiply(BigInteger.valueOf(2)).add(BigInteger.valueOf(1));
615                                if (bigValue.compareTo(maxRange) > 0)
616                                    throw new NumberFormatException("Value out of range. Value:\"" + newValue + "\"");
617                            }
618                            else {
619                                Long.parseLong((String) newValue);
620                            }
621                        }
622                        else {
623                            /* Floating-point type */
624                            Double.parseDouble((String) newValue);
625                        }
626                        break;
627
628                    default:
629                        throw new ValidationFailedException("No validation logic for numerical data of size " + datasetDatatype.getDatatypeSize());
630                }
631            }
632            catch (Exception ex) {
633                super.throwValidationFailedException(rowIndex, colIndex, newValue, ex.toString());
634            }
635            finally {
636                log.trace("validate({}, {}, {}): finish", rowIndex, colIndex, newValue);
637            }
638
639            return true;
640        }
641    }
642
643    private static class EnumDataValidator extends HDFDataValidator {
644        private final HDFDataValidator baseValidator;
645
646        EnumDataValidator(final Datatype dtype) throws Exception {
647            super(dtype);
648
649            log = org.slf4j.LoggerFactory.getLogger(EnumDataValidator.class);
650
651            if (!dtype.isEnum()) {
652                log.debug("datatype is not an enum type: exit");
653                throw new Exception("EnumDataValidator: datatype is not an enum type");
654            }
655
656            Datatype baseType = dtype.getDatatypeBase();
657            if (baseType == null) {
658                log.debug("base datatype is null: exit");
659                throw new Exception("EnumDataValidator: base datatype is null");
660            }
661            if (!baseType.isInteger()) {
662                log.debug("base datatype is not an integer type: exit");
663                throw new Exception("EnumDataValidator: datatype is not an integer type");
664            }
665
666            log.trace("base Datatype is {}", dtype.getDescription());
667
668            try {
669                baseValidator = getDataValidator(baseType);
670            }
671            catch (Exception ex) {
672                log.debug("couldn't get DataValidator for base datatype: exit: ", ex);
673                throw new Exception("couldn't get DataValidator for base datatype: " + ex.getMessage());
674            }
675        }
676
677        @Override
678        public boolean validate(int colIndex, int rowIndex, Object newValue) {
679            log.trace("validate({}, {}, {}): start", rowIndex, colIndex, newValue);
680
681            try {
682                super.checkValidValue(newValue);
683
684                baseValidator.validate(colIndex, rowIndex, newValue);
685            }
686            catch (Exception ex) {
687                super.throwValidationFailedException(rowIndex, colIndex, newValue, ex.toString());
688            }
689            finally {
690                log.trace("validate({}, {}, {}): finish", rowIndex, colIndex, newValue);
691            }
692
693            return true;
694        }
695    }
696
697    private static class BitfieldDataValidator extends HDFDataValidator {
698        BitfieldDataValidator(final Datatype dtype) {
699            super(dtype);
700
701            log = org.slf4j.LoggerFactory.getLogger(BitfieldDataValidator.class);
702        }
703    }
704
705    private static class RefDataValidator extends HDFDataValidator {
706        RefDataValidator(final Datatype dtype) {
707            super(dtype);
708
709            log = org.slf4j.LoggerFactory.getLogger(RefDataValidator.class);
710        }
711    }
712
713}