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