001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * All rights reserved. * 004 * * 005 * This file is part of the HDF Java Products distribution. * 006 * The full copyright notice, including terms governing use, modification, * 007 * and redistribution, is contained in the files COPYING and Copyright.html. * 008 * COPYING can be found at the root of the source code distribution tree. * 009 * Or, see https://support.hdfgroup.org/products/licenses.html * 010 * If you do not have access to either file, you may request a copy from * 011 * help@hdfgroup.org. * 012 ****************************************************************************/ 013 014package hdf.view.TableView; 015 016import java.lang.reflect.Array; 017import java.math.BigInteger; 018import java.util.HashMap; 019import java.util.List; 020import java.util.StringTokenizer; 021 022import org.eclipse.nebula.widgets.nattable.data.IDataProvider; 023 024import hdf.object.CompoundDataFormat; 025import hdf.object.DataFormat; 026import hdf.object.Datatype; 027import hdf.object.Utils; 028import hdf.view.Tools; 029 030/** 031 * A Factory class to return a concrete class implementing the IDataProvider 032 * interface in order to provide data for a NatTable. 033 * 034 * @author Jordan T. Henderson 035 * @version 1.0 2/9/2019 036 * 037 */ 038public class DataProviderFactory 039{ 040 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DataProviderFactory.class); 041 042 /** 043 * To keep things clean from an API perspective, keep a static reference to the last 044 * DataFormat that was passed in. This keeps us from needing to pass the DataFormat 045 * object as a parameter to every DataProvider class, since it's really only needed 046 * during the HDFDataProvider constructor. 047 */ 048 private static DataFormat dataFormatReference = null; 049 050 /** 051 * Get the Data Display Provider for the supplied data object 052 * 053 * @param dataObject 054 * the data object 055 * @param dataBuf 056 * the data buffer to use 057 * @param dataTransposed 058 * if the data should be transposed 059 * 060 * @return the provider instance 061 * 062 * @throws Exception if a failure occurred 063 */ 064 public static HDFDataProvider getDataProvider(final DataFormat dataObject, final Object dataBuf, final boolean dataTransposed) throws Exception { 065 if (dataObject == null) { 066 log.debug("getDataProvider(DataFormat): data object is null"); 067 return null; 068 } 069 070 dataFormatReference = dataObject; 071 072 HDFDataProvider dataProvider = getDataProvider(dataObject.getDatatype(), dataBuf, dataTransposed); 073 074 return dataProvider; 075 } 076 077 private static final HDFDataProvider getDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed) throws Exception { 078 HDFDataProvider dataProvider = null; 079 080 try { 081 if (dtype.isCompound()) 082 dataProvider = new CompoundDataProvider(dtype, dataBuf, dataTransposed); 083 else if (dtype.isArray()) 084 dataProvider = new ArrayDataProvider(dtype, dataBuf, dataTransposed); 085 else if (dtype.isVLEN() && !dtype.isVarStr()) 086 dataProvider = new VlenDataProvider(dtype, dataBuf, dataTransposed); 087 else if (dtype.isString() || dtype.isVarStr()) 088 dataProvider = new StringDataProvider(dtype, dataBuf, dataTransposed); 089 else if (dtype.isChar()) 090 dataProvider = new CharDataProvider(dtype, dataBuf, dataTransposed); 091 else if (dtype.isInteger() || dtype.isFloat()) 092 dataProvider = new NumericalDataProvider(dtype, dataBuf, dataTransposed); 093 else if (dtype.isEnum()) 094 dataProvider = new EnumDataProvider(dtype, dataBuf, dataTransposed); 095 else if (dtype.isOpaque() || dtype.isBitField()) 096 dataProvider = new BitfieldDataProvider(dtype, dataBuf, dataTransposed); 097 else if (dtype.isRef()) 098 dataProvider = new RefDataProvider(dtype, dataBuf, dataTransposed); 099 } 100 catch (Exception ex) { 101 log.debug("getDataProvider(): error occurred in retrieving a DataProvider: ", ex); 102 dataProvider = null; 103 } 104 105 /* 106 * Try to use a default DataProvider. 107 */ 108 if (dataProvider == null) { 109 log.debug("getDataProvider(): using a default data provider"); 110 111 dataProvider = new HDFDataProvider(dtype, dataBuf, dataTransposed); 112 } 113 114 return dataProvider; 115 } 116 117 /** 118 * The base DataProvider which pulls data from a given Array object using direct 119 * indices. 120 */ 121 public static class HDFDataProvider implements IDataProvider 122 { 123 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(HDFDataProvider.class); 124 125 /** 126 * In order to support 3-dimensional datasets, which may need to update the data 127 * buffer object after flipping through a 'page', this field is not marked as 128 * final. However, it is important that subclasses DO NOT override this field. 129 */ 130 protected Object dataBuf; 131 132 /** the data value */ 133 protected Object theValue; 134 135 /** the data format class */ 136 protected final Class originalFormatClass; 137 138 /** if the data value has changed */ 139 protected boolean isValueChanged; 140 141 /** the type of the parent*/ 142 protected final boolean isContainerType; 143 144 /** the rank */ 145 protected final int rank; 146 147 /** if the data is in original order */ 148 protected final boolean isNaturalOrder; 149 /** if the data is transposed */ 150 protected final boolean isDataTransposed; 151 152 /** the column */ 153 protected long colCount; 154 /** the row */ 155 protected long rowCount; 156 157 /** 158 * Create the HDF extended Data Display Provider for the supplied data object 159 * 160 * @param dtype 161 * the datatype object 162 * @param dataBuf 163 * the data buffer to use 164 * @param dataTransposed 165 * if the data should be transposed 166 * 167 * @throws Exception if a failure occurred 168 */ 169 HDFDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed) throws Exception { 170 this.dataBuf = dataBuf; 171 172 this.originalFormatClass = dataFormatReference.getOriginalClass(); 173 174 char runtimeTypeClass = Utils.getJavaObjectRuntimeClass(dataBuf); 175 if (runtimeTypeClass == ' ') { 176 log.debug("invalid data value runtime type class: runtimeTypeClass={}", runtimeTypeClass); 177 throw new IllegalStateException("Invalid data value runtime type class: " + runtimeTypeClass); 178 } 179 180 rank = dataFormatReference.getRank(); 181 182 isNaturalOrder = ((rank == 1) || (dataFormatReference.getSelectedIndex()[0] < dataFormatReference.getSelectedIndex()[1])); 183 isDataTransposed = dataTransposed; 184 185 if (rank > 1) { 186 rowCount = dataFormatReference.getHeight(); 187 colCount = dataFormatReference.getWidth(); 188 } 189 else { 190 rowCount = (int) dataFormatReference.getSelectedDims()[0]; 191 colCount = 1; 192 } 193 log.trace("constructor: rowCount={} colCount={}", rowCount, colCount); 194 195 theValue = null; 196 isValueChanged = false; 197 198 isContainerType = (this instanceof CompoundDataProvider 199 || this instanceof ArrayDataProvider 200 || this instanceof VlenDataProvider); 201 } 202 203 /** 204 * A utility method used to translate a set of physical table coordinates to an 205 * index into a data buffer. 206 * 207 * @param rowIndex 208 * the row 209 * @param columnIndex 210 * the column 211 * 212 * @return physical location in 1D notation 213 */ 214 public int physicalLocationToBufIndex(int rowIndex, int columnIndex) { 215 long index = rowIndex * colCount + columnIndex; 216 217 if (rank > 1) { 218 log.trace("physicalLocationToBufIndex({}, {}): rank > 1; adjusting for multi-dimensional dataset", rowIndex, columnIndex); 219 220 if (isDataTransposed && isNaturalOrder) 221 index = columnIndex * rowCount + rowIndex; 222 else if (!isDataTransposed && !isNaturalOrder) 223 // Reshape Data 224 index = rowIndex * colCount + columnIndex; 225 else if (isDataTransposed && !isNaturalOrder) 226 // Transpose Data 227 index = columnIndex * rowCount + rowIndex; 228 else 229 index = rowIndex * colCount + columnIndex; 230 } 231 232 log.trace("physicalLocationToBufIndex({}, {}, {}): finish", rowIndex, columnIndex, index); 233 234 return (int) index; 235 } 236 237 @Override 238 public Object getDataValue(int columnIndex, int rowIndex) { 239 try { 240 int bufIndex = physicalLocationToBufIndex(rowIndex, columnIndex); 241 242 theValue = Array.get(dataBuf, bufIndex); 243 } 244 catch (Exception ex) { 245 log.debug("getDataValue({}, {}): failure: ", rowIndex, columnIndex, ex); 246 theValue = DataFactoryUtils.errStr; 247 } 248 249 log.trace("getDataValue({}, {})=({}): finish", rowIndex, columnIndex, theValue); 250 251 return theValue; 252 } 253 254 /** 255 * When a CompoundDataProvider wants to pass a List of data down to a nested 256 * CompoundDataProvider, or when a top-level container DataProvider (such as an 257 * ArrayDataProvider) wants to hand data down to a base CompoundDataProvider, we 258 * need to pass down a List of data, plus a field and row index. This method is 259 * for facilitating this behavior. 260 * 261 * In general, all "container" DataProviders that have a "container" base 262 * DataProvider should call down into their base DataProvider(s) using this 263 * method, in order to ensure that buried CompoundDataProviders get handled 264 * correctly. When their base DataProvider is not a "container" type, the method 265 * getDataValue(Object, index) should be used instead. 266 * 267 * For atomic type DataProviders, we treat this method as directly calling into 268 * getDataValue(Object, index) using the passed rowIndex. However, this method 269 * should, in general, not be called by atomic type DataProviders. 270 * 271 * @param obj 272 * the data object 273 * @param rowIndex 274 * the row 275 * @param columnIndex 276 * the column 277 * 278 * @return value of the data 279 */ 280 public Object getDataValue(Object obj, int columnIndex, int rowIndex) { 281 return getDataValue(obj, rowIndex); 282 } 283 284 /** 285 * When a parent HDFDataProvider (such as an ArrayDataProvider) wants to 286 * retrieve a data value by routing the operation through its base 287 * HDFDataProvider, the parent HDFDataProvider will generally know the direct 288 * index to have the base provider use. This method is to facilitate this kind 289 * of behavior. 290 * 291 * Note that this method takes an Object parameter, which is the object that the 292 * method should pull its data from. This is to be able to nicely support nested 293 * compound DataProviders. 294 * 295 * @param obj 296 * the data object 297 * @param index 298 * the index into the data array 299 * 300 * @return the data object 301 */ 302 public Object getDataValue(Object obj, int index) { 303 try { 304 theValue = Array.get(obj, index); 305 } 306 catch (Exception ex) { 307 log.debug("getDataValue({}): failure: ", index, ex); 308 theValue = DataFactoryUtils.errStr; 309 } 310 311 log.trace("getDataValue({})=({}): finish", index, theValue); 312 313 return theValue; 314 } 315 316 /** 317 * update the data value of a compound type. 318 * 319 * @param columnIndex 320 * the column 321 * @param rowIndex 322 * the row 323 * @param newValue 324 * the new data value object 325 */ 326 @Override 327 public void setDataValue(int columnIndex, int rowIndex, Object newValue) { 328 try { 329 int bufIndex = physicalLocationToBufIndex(rowIndex, columnIndex); 330 331 updateAtomicValue(dataBuf, newValue, bufIndex); 332 } 333 catch (Exception ex) { 334 log.debug("setDataValue({}, {})=({}): cell value update failure: ", rowIndex, columnIndex, newValue, ex); 335 } 336 log.trace("setDataValue({}, {})=({}): finish", rowIndex, columnIndex, newValue); 337 338 /* 339 * TODO: throwing error dialogs when something fails? 340 * 341 * Tools.showError(shell, "Select", "Unable to set new value:\n\n " + ex); 342 */ 343 } 344 345 /** 346 * When a CompoundDataProvider wants to pass a List of data down to a nested 347 * CompoundDataProvider, or when a top-level container DataProvider (such as an 348 * ArrayDataProvider) wants to hand data down to a base CompoundDataProvider, we 349 * need to pass down a List of data and the new value, plus a field and row 350 * index. This method is for facilitating this behavior. 351 * 352 * In general, all "container" DataProviders that have a "container" base 353 * DataProvider should call down into their base DataProvider(s) using this{}, 354 * method, in order to ensure that buried CompoundDataProviders get handled 355 * correctly. When their base DataProvider is not a "container" type, the method 356 * setDataValue(index, Object, Object) should be used instead. 357 * 358 * For atomic type DataProviders, we treat this method as directly calling into 359 * setDataValue(index, Object, Object) using the passed rowIndex. However, this 360 * method should, in general, not be called by atomic type DataProviders. 361 * 362 * @param columnIndex 363 * the column 364 * @param rowIndex 365 * the row 366 * @param bufObject 367 * the data object 368 * @param newValue 369 * the new data object 370 */ 371 public void setDataValue(int columnIndex, int rowIndex, Object bufObject, Object newValue) { 372 setDataValue(rowIndex, bufObject, newValue); 373 } 374 375 /** 376 * When a parent HDFDataProvider (such as an ArrayDataProvider) wants to set a 377 * data value by routing the operation through its base HDFDataProvider, the 378 * parent HDFDataProvider will generally know the direct index to have the base 379 * provider use. This method is to facilitate this kind of behavior. 380 * 381 * Note that this method takes two Object parameters, one which is the object 382 * that the method should set its data inside of and one which is the new value 383 * to set. This is to be able to nicely support nested compound DataProviders. 384 * 385 * @param index 386 * the index into the data array 387 * @param bufObject 388 * the data object 389 * @param newValue 390 * the new data object 391 */ 392 public void setDataValue(int index, Object bufObject, Object newValue) { 393 try { 394 updateAtomicValue(bufObject, newValue, index); 395 } 396 catch (Exception ex) { 397 log.debug("setDataValue({}, {})=({}): updateAtomicValue failure: ", index, bufObject, newValue, ex); 398 } 399 log.trace("setDataValue({}, {})=({}): finish", index, bufObject, newValue); 400 } 401 402 private void updateAtomicValue(Object bufObject, Object newValue, int bufIndex) { 403 if ((newValue == null) || ((newValue = ((String) newValue).trim()) == null)) { 404 log.debug("updateAtomicValue(): cell value not updated; new value is null"); 405 return; 406 } 407 408 // No need to update if values are the same 409 Object oldVal = this.getDataValue(bufObject, bufIndex); 410 if ((oldVal != null) && newValue.equals(oldVal.toString())) { 411 log.debug("updateAtomicValue(): cell value not updated; new value same as old value"); 412 return; 413 } 414 415 char runtimeTypeClass = Utils.getJavaObjectRuntimeClass(bufObject); 416 417 log.trace("updateAtomicValue(): runtimeTypeClass={}", runtimeTypeClass); 418 419 switch (runtimeTypeClass) { 420 case 'B': 421 byte bvalue = 0; 422 bvalue = Byte.parseByte((String) newValue); 423 Array.setByte(bufObject, bufIndex, bvalue); 424 break; 425 case 'S': 426 short svalue = 0; 427 svalue = Short.parseShort((String) newValue); 428 Array.setShort(bufObject, bufIndex, svalue); 429 break; 430 case 'I': 431 int ivalue = 0; 432 ivalue = Integer.parseInt((String) newValue); 433 Array.setInt(bufObject, bufIndex, ivalue); 434 break; 435 case 'J': 436 long lvalue = 0; 437 String cname = this.originalFormatClass.getName(); 438 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 439 if (dname == 'J') { 440 BigInteger big = new BigInteger((String) newValue); 441 lvalue = big.longValue(); 442 } 443 else 444 lvalue = Long.parseLong((String) newValue); 445 Array.setLong(bufObject, bufIndex, lvalue); 446 break; 447 case 'F': 448 float fvalue = 0; 449 fvalue = Float.parseFloat((String) newValue); 450 Array.setFloat(bufObject, bufIndex, fvalue); 451 break; 452 case 'D': 453 double dvalue = 0; 454 dvalue = Double.parseDouble((String) newValue); 455 Array.setDouble(bufObject, bufIndex, dvalue); 456 break; 457 default: 458 Array.set(bufObject, bufIndex, newValue); 459 break; 460 } 461 462 isValueChanged = true; 463 } 464 465 @Override 466 public int getColumnCount() { 467 return (int) colCount; 468 } 469 470 @Override 471 public int getRowCount() { 472 return (int) rowCount; 473 } 474 475 /** 476 * set if the data value has changed 477 * 478 * @param isChanged 479 * if the data value is changed 480 */ 481 public final void setIsValueChanged(boolean isChanged) { 482 isValueChanged = isChanged; 483 } 484 485 /** 486 * @return if the datavalue has chaged 487 */ 488 public final boolean getIsValueChanged() { 489 return isValueChanged; 490 } 491 492 /** 493 * Update the data buffer for this HDFDataProvider. This is necessary for when 494 * the data that has been read is invalidated, such as when flipping through 495 * 'pages' in a > 2-dimensional dataset. 496 * 497 * @param newBuf 498 * the new data buffer 499 */ 500 public final void updateDataBuffer(Object newBuf) { 501 this.dataBuf = newBuf; 502 503 if (rank > 1) { 504 rowCount = dataFormatReference.getHeight(); 505 colCount = dataFormatReference.getWidth(); 506 } 507 else { 508 rowCount = (int) dataFormatReference.getSelectedDims()[0]; 509 colCount = 1; 510 } 511 log.trace("updateDataBuffer: rowCount={} colCount={}", rowCount, colCount); 512 } 513 } 514 515 /* 516 * A DataProvider for Compound datatype datasets which is a composite of 517 * DataProviders, one for each selected member of the Compound datatype. 518 */ 519 private static class CompoundDataProvider extends HDFDataProvider 520 { 521 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CompoundDataProvider.class); 522 523 private final HashMap<Integer, Integer> baseProviderIndexMap; 524 private final HashMap<Integer, Integer> relCmpdStartIndexMap; 525 526 private final HDFDataProvider[] baseTypeProviders; 527 528 private final Datatype[] selectedMemberTypes; 529 530 private final int[] selectedMemberOrders; 531 532 private final int nSubColumns; 533 private final int nCols; 534 private final int nRows; 535 536 CompoundDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed) throws Exception { 537 super(dtype, dataBuf, dataTransposed); 538 539 CompoundDataFormat compoundFormat = (CompoundDataFormat) dataFormatReference; 540 selectedMemberTypes = compoundFormat.getSelectedMemberTypes(); 541 selectedMemberOrders = compoundFormat.getSelectedMemberOrders(); 542 543 List<Datatype> localSelectedTypes = DataFactoryUtils.filterNonSelectedMembers(compoundFormat, dtype); 544 545 log.trace("setting up {} base HDFDataProviders", localSelectedTypes.size()); 546 547 baseTypeProviders = new HDFDataProvider[localSelectedTypes.size()]; 548 for (int i = 0; i < baseTypeProviders.length; i++) { 549 log.trace("retrieving DataProvider for member {}", i); 550 551 try { 552 baseTypeProviders[i] = getDataProvider(localSelectedTypes.get(i), dataBuf, dataTransposed); 553 } 554 catch (Exception ex) { 555 log.debug("failed to retrieve DataProvider for member {}: ", i, ex); 556 baseTypeProviders[i] = null; 557 } 558 } 559 560 /* 561 * Build necessary index maps. 562 */ 563 HashMap<Integer, Integer>[] maps = DataFactoryUtils.buildIndexMaps(compoundFormat, localSelectedTypes); 564 baseProviderIndexMap = maps[DataFactoryUtils.COL_TO_BASE_CLASS_MAP_INDEX]; 565 relCmpdStartIndexMap = maps[DataFactoryUtils.CMPD_START_IDX_MAP_INDEX]; 566 567 log.trace("index maps built: baseProviderIndexMap = {}, relColIdxMap = {}", 568 baseProviderIndexMap.toString(), relCmpdStartIndexMap.toString()); 569 570 if (baseProviderIndexMap.size() == 0) { 571 log.debug("base DataProvider index mapping is invalid - size 0"); 572 throw new Exception("CompoundDataProvider: invalid DataProvider mapping of size 0 built"); 573 } 574 575 if (relCmpdStartIndexMap.size() == 0) { 576 log.debug("compound field start index mapping is invalid - size 0"); 577 throw new Exception("CompoundDataProvider: invalid compound field start index mapping of size 0 built"); 578 } 579 580 /* 581 * nCols should represent the number of columns covered by this CompoundDataProvider 582 * only. For top-level CompoundDataProviders, this should be the entire width of the 583 * dataset. For nested CompoundDataProviders, nCols will be a subset of these columns. 584 */ 585 nCols = (int) compoundFormat.getWidth() * baseProviderIndexMap.size(); 586 nRows = (int) compoundFormat.getHeight(); 587 588 nSubColumns = (int) compoundFormat.getWidth(); 589 } 590 591 @Override 592 public Object getDataValue(int columnIndex, int rowIndex) { 593 try { 594 int fieldIdx = columnIndex; 595 int rowIdx = rowIndex; 596 597 if (nSubColumns > 1) { // multi-dimension compound dataset 598 /* 599 * Make sure fieldIdx is within a valid range, since even for multi-dimensional 600 * compound datasets there will only be as many lists of data as there are 601 * members in a single compound type. 602 */ 603 fieldIdx %= selectedMemberTypes.length; 604 605 int realColIdx = columnIndex / selectedMemberTypes.length; 606 rowIdx = rowIndex * nSubColumns + realColIdx; 607 } 608 609 int providerIndex = baseProviderIndexMap.get(fieldIdx); 610 Object colValue = ((List<?>) dataBuf).get(providerIndex); 611 if (colValue == null) 612 return DataFactoryUtils.nullStr; 613 614 /* 615 * Delegate data retrieval to one of the base DataProviders according to the 616 * index of the relevant compound field. 617 */ 618 HDFDataProvider base = baseTypeProviders[providerIndex]; 619 if (base instanceof CompoundDataProvider) 620 /* 621 * Adjust the compound field index by subtracting the starting index of the 622 * nested compound that we are delegating to. When the nested compound's index 623 * map is setup correctly, this adjusted index should map to the correct field 624 * among the nested compound's members. 625 */ 626 theValue = base.getDataValue(colValue, fieldIdx - relCmpdStartIndexMap.get(fieldIdx), rowIdx); 627 else if (base instanceof ArrayDataProvider) { 628 /* 629 * TODO: quick temporary fix for specific compound of array of compound files. 630 * Transforms the given column index into a relative index from the starting 631 * index of the array of compound field. 632 */ 633 int arrCompoundStartIdx = columnIndex; 634 HDFDataProvider theProvider; 635 while (arrCompoundStartIdx >= 0) { 636 try { 637 theProvider = baseTypeProviders[baseProviderIndexMap.get(arrCompoundStartIdx - 1)]; 638 if (theProvider != base) 639 break; 640 641 arrCompoundStartIdx--; 642 } 643 catch (Exception ex) { 644 break; 645 } 646 } 647 648 int adjustedColIndex = columnIndex - arrCompoundStartIdx; 649 650 theValue = base.getDataValue(colValue, adjustedColIndex, rowIdx); 651 } 652 else 653 theValue = base.getDataValue(colValue, rowIdx); 654 } 655 catch (Exception ex) { 656 log.debug("getDataValue({}, {}): failure: ", rowIndex, columnIndex, ex); 657 theValue = DataFactoryUtils.errStr; 658 } 659 660 log.trace("getDataValue({}, {}): finish", rowIndex, columnIndex); 661 662 return theValue; 663 } 664 665 @Override 666 public Object getDataValue(Object obj, int columnIndex, int rowIndex) { 667 try { 668 int providerIndex = baseProviderIndexMap.get(columnIndex); 669 Object colValue = ((List<?>) obj).get(providerIndex); 670 if (colValue == null) 671 return DataFactoryUtils.nullStr; 672 673 /* 674 * Delegate data retrieval to one of the base DataProviders according to the 675 * index of the relevant compound field. 676 */ 677 HDFDataProvider base = baseTypeProviders[providerIndex]; 678 if (base instanceof CompoundDataProvider) 679 /* 680 * Adjust the compound field index by subtracting the starting index of the 681 * nested compound that we are delegating to. When the nested compound's index 682 * map is setup correctly, this adjusted index should map to the correct field 683 * among the nested compound's members. 684 */ 685 theValue = base.getDataValue(colValue, columnIndex - relCmpdStartIndexMap.get(columnIndex), rowIndex); 686 else if (base instanceof ArrayDataProvider) 687 theValue = base.getDataValue(colValue, columnIndex, rowIndex); 688 else 689 theValue = base.getDataValue(colValue, rowIndex); 690 } 691 catch (Exception ex) { 692 log.debug("getDataValue({}, {}): failure: ", rowIndex, columnIndex, ex); 693 theValue = DataFactoryUtils.errStr; 694 } 695 log.trace("getDataValue({})=({}): finish", rowIndex, columnIndex); 696 697 return theValue; 698 } 699 700 @Override 701 public Object getDataValue(Object obj, int index) { 702 throw new UnsupportedOperationException("getDataValue(Object, int) should not be called for CompoundDataProviders"); 703 } 704 705 @Override 706 public void setDataValue(int columnIndex, int rowIndex, Object newValue) { 707 if ((newValue == null) || ((newValue = ((String) newValue).trim()) == null)) { 708 log.debug("setDataValue({}, {})=({}): cell value not updated; new value is null", rowIndex, columnIndex, newValue); 709 return; 710 } 711 712 // No need to update if values are the same 713 Object oldVal = this.getDataValue(columnIndex, rowIndex); 714 if ((oldVal != null) && newValue.equals(oldVal.toString())) { 715 log.debug("setDataValue({}, {})=({}): cell value not updated; new value same as old value", rowIndex, columnIndex, newValue); 716 return; 717 } 718 719 try { 720 int fieldIdx = columnIndex; 721 int rowIdx = rowIndex; 722 723 if (nSubColumns > 1) { // multi-dimension compound dataset 724 /* 725 * Make sure fieldIdx is within a valid range, since even for multi-dimensional 726 * compound datasets there will only be as many lists of data as there are 727 * members in a single compound type. 728 */ 729 fieldIdx %= selectedMemberTypes.length; 730 731 int realColIdx = columnIndex / selectedMemberTypes.length; 732 rowIdx = rowIndex * nSubColumns + realColIdx; 733 } 734 735 int providerIndex = baseProviderIndexMap.get(fieldIdx); 736 Object colValue = ((List<?>) dataBuf).get(providerIndex); 737 if (colValue == null) { 738 log.debug("setDataValue({}, {})=({}): colValue is null", rowIndex, columnIndex, newValue); 739 return; 740 } 741 742 /* 743 * Delegate data setting to one of the base DataProviders according to the index 744 * of the relevant compound field. 745 */ 746 HDFDataProvider base = baseTypeProviders[providerIndex]; 747 if (base.isContainerType) 748 /* 749 * Adjust the compound field index by subtracting the starting index of the 750 * nested compound that we are delegating to. When the nested compound's index 751 * map is setup correctly, this adjusted index should map to the correct field 752 * among the nested compound's members. 753 */ 754 base.setDataValue(fieldIdx - relCmpdStartIndexMap.get(fieldIdx), rowIdx, colValue, newValue); 755 else 756 base.setDataValue(rowIdx, colValue, newValue); 757 758 isValueChanged = true; 759 } 760 catch (Exception ex) { 761 log.debug("setDataValue({}, {})=({}): cell value update failure: ", rowIndex, columnIndex, newValue); 762 } 763 log.trace("setDataValue({}, {})=({}): finish", rowIndex, columnIndex, newValue); 764 765 /* 766 * TODO: throwing error dialogs when something fails? 767 * 768 * Tools.showError(shell, "Select", "Unable to set new value:\n\n " + ex); 769 */ 770 } 771 772 @Override 773 public void setDataValue(int columnIndex, int rowIndex, Object bufObject, Object newValue) { 774 try { 775 int providerIndex = baseProviderIndexMap.get(columnIndex); 776 Object colValue = ((List<?>) bufObject).get(providerIndex); 777 if (colValue == null) { 778 log.debug("setDataValue({}, {}, {})=({}): colValue is null", rowIndex, columnIndex, bufObject, newValue); 779 return; 780 } 781 782 /* 783 * Delegate data setting to one of the base DataProviders according to the index 784 * of the relevant compound field. 785 */ 786 HDFDataProvider base = baseTypeProviders[providerIndex]; 787 if (base.isContainerType) 788 /* 789 * Adjust the compound field index by subtracting the starting index of the 790 * nested compound that we are delegating to. When the nested compound's index 791 * map is setup correctly, this adjusted index should map to the correct field 792 * among the nested compound's members. 793 */ 794 base.setDataValue(columnIndex - relCmpdStartIndexMap.get(columnIndex), rowIndex, colValue, newValue); 795 else 796 base.setDataValue(rowIndex, colValue, newValue); 797 798 isValueChanged = true; 799 } 800 catch (Exception ex) { 801 log.debug("setDataValue({}, {}, {})=({}): cell value update failure: ", rowIndex, columnIndex, bufObject, newValue, ex); 802 } 803 log.trace("setDataValue({}, {}, {})=({}): finish", rowIndex, columnIndex, bufObject, newValue); 804 } 805 806 @Override 807 public void setDataValue(int index, Object bufObject, Object newValue) { 808 throw new UnsupportedOperationException("setDataValue(int, Object, Object) should not be called for CompoundDataProviders"); 809 } 810 811 @Override 812 public int getColumnCount() { 813 return nCols; 814 } 815 816 @Override 817 public int getRowCount() { 818 return nRows; 819 } 820 } 821 822 private static class ArrayDataProvider extends HDFDataProvider 823 { 824 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ArrayDataProvider.class); 825 826 private final HDFDataProvider baseTypeDataProvider; 827 828 private final Object[] arrayElements; 829 private final long arraySize; 830 831 private final int nCols; 832 833 ArrayDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed) throws Exception { 834 super(dtype, dataBuf, dataTransposed); 835 836 Datatype baseType = dtype.getDatatypeBase(); 837 838 baseTypeDataProvider = getDataProvider(baseType, dataBuf, dataTransposed); 839 840 if (baseType.isVarStr()) 841 arraySize = dtype.getArrayDims()[0]; 842 else if (baseType.isBitField() || baseType.isOpaque()) 843 arraySize = dtype.getDatatypeSize(); 844 else 845 arraySize = dtype.getDatatypeSize() / baseType.getDatatypeSize(); 846 847 arrayElements = new Object[(int) arraySize]; 848 849 if (baseTypeDataProvider instanceof CompoundDataProvider) 850 nCols = (int) arraySize * ((CompoundDataProvider) baseTypeDataProvider).nCols; 851 else 852 nCols = super.getColumnCount(); 853 } 854 855 @Override 856 public Object getDataValue(int columnIndex, int rowIndex) { 857 try { 858 int bufIndex = physicalLocationToBufIndex(rowIndex, columnIndex); 859 860 bufIndex *= arraySize; 861 862 if (baseTypeDataProvider instanceof CompoundDataProvider) { 863 /* 864 * Pass row and column indices down where they will be adjusted. 865 */ 866 theValue = retrieveArrayOfCompoundElements(dataBuf, columnIndex, rowIndex); 867 } 868 else if (baseTypeDataProvider instanceof ArrayDataProvider) { 869 /* 870 * TODO: assign to global arrayElements. 871 */ 872 theValue = retrieveArrayOfArrayElements(dataBuf, columnIndex, bufIndex); 873 } 874 else { 875 /* 876 * TODO: assign to global arrayElements. 877 */ 878 theValue = retrieveArrayOfAtomicElements(dataBuf, bufIndex); 879 } 880 } 881 catch (Exception ex) { 882 log.debug("getDataValue({}, {}): failure: ", rowIndex, columnIndex, ex); 883 theValue = DataFactoryUtils.errStr; 884 } 885 886 log.trace("getDataValue({}, {})({}): finish", rowIndex, columnIndex, theValue); 887 888 return theValue; 889 } 890 891 @Override 892 public Object getDataValue(Object obj, int columnIndex, int rowIndex) { 893 try { 894 long index = rowIndex * arraySize; 895 896 if (baseTypeDataProvider instanceof CompoundDataProvider) { 897 /* 898 * Pass row and column indices down where they will be adjusted. 899 */ 900 theValue = retrieveArrayOfCompoundElements(obj, columnIndex, rowIndex); 901 } 902 else if (baseTypeDataProvider instanceof ArrayDataProvider) { 903 theValue = retrieveArrayOfArrayElements(obj, columnIndex, (int) index); 904 } 905 else { 906 theValue = retrieveArrayOfAtomicElements(obj, (int) index); 907 } 908 } 909 catch (Exception ex) { 910 log.debug("getDataValue({}, {}): failure: ", rowIndex, columnIndex, ex); 911 theValue = DataFactoryUtils.errStr; 912 } 913 914 return theValue; 915 } 916 917 private Object[] retrieveArrayOfCompoundElements(Object objBuf, int columnIndex, int rowIndex) { 918 long adjustedRowIdx = (rowIndex * arraySize * colCount) 919 + (columnIndex / ((CompoundDataProvider) baseTypeDataProvider).baseProviderIndexMap.size()); 920 long adjustedColIdx = columnIndex % ((CompoundDataProvider) baseTypeDataProvider).baseProviderIndexMap.size(); 921 922 /* 923 * Since we flatten array of compound types, we only need to return a single 924 * value. 925 */ 926 return new Object[] { baseTypeDataProvider.getDataValue(objBuf, (int) adjustedColIdx, (int) adjustedRowIdx) }; 927 } 928 929 private Object[] retrieveArrayOfArrayElements(Object objBuf, int columnIndex, int startRowIndex) { 930 Object[] tempArray = new Object[(int) arraySize]; 931 932 for (int i = 0; i < arraySize; i++) 933 tempArray[i] = baseTypeDataProvider.getDataValue(objBuf, columnIndex, startRowIndex + i); 934 935 return tempArray; 936 } 937 938 private Object[] retrieveArrayOfAtomicElements(Object objBuf, int rowStartIdx) { 939 Object[] tempArray = new Object[(int) arraySize]; 940 941 for (int i = 0; i < arraySize; i++) 942 tempArray[i] = baseTypeDataProvider.getDataValue(objBuf, rowStartIdx + i); 943 944 return tempArray; 945 } 946 947 @Override 948 public Object getDataValue(Object obj, int index) { 949 throw new UnsupportedOperationException("getDataValue(Object, int) should not be called for ArrayDataProviders"); 950 } 951 952 @Override 953 public void setDataValue(int columnIndex, int rowIndex, Object newValue) { 954 try { 955 int bufIndex = physicalLocationToBufIndex(rowIndex, columnIndex); 956 957 bufIndex *= arraySize; 958 959 updateArrayElements(dataBuf, newValue, columnIndex, bufIndex); 960 } 961 catch (Exception ex) { 962 log.debug("setDataValue({}, {}, {}): cell value update failure: ", rowIndex, columnIndex, newValue, ex); 963 } 964 log.trace("setDataValue({}, {})=({}): finish", rowIndex, columnIndex, newValue); 965 } 966 967 @Override 968 public void setDataValue(int columnIndex, int rowIndex, Object bufObject, Object newValue) { 969 try { 970 long bufIndex = rowIndex * arraySize; 971 972 updateArrayElements(bufObject, newValue, columnIndex, (int) bufIndex); 973 } 974 catch (Exception ex) { 975 log.debug("setDataValue({}, {}, {}, {}): cell value update failure: ", rowIndex, columnIndex, bufObject, newValue, ex); 976 } 977 log.trace("setDataValue({}, {}, {})=({}): finish", rowIndex, columnIndex, bufObject, newValue); 978 } 979 980 @Override 981 public void setDataValue(int index, Object bufObject, Object newValue) { 982 throw new UnsupportedOperationException("setDataValue(int, Object, Object) should not be called for ArrayDataProviders"); 983 } 984 985 private void updateArrayElements(Object curBuf, Object newValue, int columnIndex, int bufStartIndex) { 986 StringTokenizer st = new StringTokenizer((String) newValue, ",[]"); 987 if (st.countTokens() < arraySize) { 988 /* 989 * TODO: 990 */ 991 /* Tools.showError(shell, "Select", "Number of data points < " + morder + "."); */ 992 log.debug("updateArrayElements(): number of data points ({}) < array size {}", st.countTokens(), arraySize); 993 log.trace("updateArrayElements({}, {}, {}): finish", curBuf, newValue, bufStartIndex); 994 return; 995 } 996 997 if (baseTypeDataProvider instanceof CompoundDataProvider) 998 updateArrayOfCompoundElements(st, curBuf, columnIndex, bufStartIndex); 999 else if (baseTypeDataProvider instanceof ArrayDataProvider) 1000 updateArrayOfArrayElements(st, curBuf, columnIndex, bufStartIndex); 1001 else 1002 updateArrayOfAtomicElements(st, curBuf, bufStartIndex); 1003 } 1004 1005 private void updateArrayOfCompoundElements(StringTokenizer tokenizer, Object curBuf, int columnIndex, int bufStartIndex) { 1006 for (int i = 0; i < arraySize; i++) { 1007 List<?> cmpdDataList = (List<?>) ((Object[]) curBuf)[i]; 1008 baseTypeDataProvider.setDataValue(columnIndex, bufStartIndex + i, cmpdDataList, 1009 tokenizer.nextToken().trim()); 1010 isValueChanged = isValueChanged || baseTypeDataProvider.getIsValueChanged(); 1011 } 1012 } 1013 1014 private void updateArrayOfArrayElements(StringTokenizer tokenizer, Object curBuf, int columnIndex, int bufStartIndex) { 1015 for (int i = 0; i < arraySize; i++) { 1016 /* 1017 * TODO: not quite right. 1018 */ 1019 baseTypeDataProvider.setDataValue(columnIndex, bufStartIndex + i, curBuf, tokenizer.nextToken().trim()); 1020 isValueChanged = isValueChanged || baseTypeDataProvider.getIsValueChanged(); 1021 } 1022 } 1023 1024 private void updateArrayOfAtomicElements(StringTokenizer tokenizer, Object curBuf, int bufStartIndex) { 1025 for (int i = 0; i < arraySize; i++) { 1026 baseTypeDataProvider.setDataValue(bufStartIndex + i, curBuf, tokenizer.nextToken().trim()); 1027 isValueChanged = isValueChanged || baseTypeDataProvider.getIsValueChanged(); 1028 } 1029 } 1030 1031 @Override 1032 public int getColumnCount() { 1033 return nCols; 1034 } 1035 } 1036 1037 private static class VlenDataProvider extends HDFDataProvider 1038 { 1039 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(VlenDataProvider.class); 1040 1041 private final HDFDataProvider baseTypeDataProvider; 1042 1043 private final StringBuilder buffer; 1044 1045 VlenDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed) throws Exception { 1046 super(dtype, dataBuf, dataTransposed); 1047 1048 Datatype baseType = dtype.getDatatypeBase(); 1049 1050 baseTypeDataProvider = getDataProvider(baseType, dataBuf, dataTransposed); 1051 1052 buffer = new StringBuilder(); 1053 } 1054 1055 @Override 1056 public Object getDataValue(int columnIndex, int rowIndex) { 1057 buffer.setLength(0); 1058 1059 try { 1060 int bufIndex = physicalLocationToBufIndex(rowIndex, columnIndex); 1061 1062 if (baseTypeDataProvider instanceof CompoundDataProvider) { 1063 /* 1064 * TODO: 1065 */ 1066 /* 1067 * buffer.append(baseTypeDataProvider.getDataValue(dataBuf, columnIndex, (int) index)); 1068 */ 1069 if (dataBuf instanceof String[]) 1070 buffer.append(Array.get(dataBuf, bufIndex)); 1071 else 1072 buffer.append("*UNSUPPORTED*"); 1073 } 1074 else if (baseTypeDataProvider instanceof ArrayDataProvider) { 1075 buffer.append(baseTypeDataProvider.getDataValue(dataBuf, columnIndex, bufIndex)); 1076 } 1077 else { 1078 buffer.append(baseTypeDataProvider.getDataValue(dataBuf, bufIndex)); 1079 } 1080 1081 theValue = buffer.toString(); 1082 } 1083 catch (Exception ex) { 1084 log.debug("getDataValue({}, {}): failure: ", rowIndex, columnIndex, ex); 1085 theValue = DataFactoryUtils.errStr; 1086 } 1087 1088 log.trace("getDataValue({}, {})=({}): finish", rowIndex, columnIndex, theValue); 1089 1090 return theValue; 1091 } 1092 1093 @Override 1094 public Object getDataValue(Object obj, int columnIndex, int rowIndex) { 1095 buffer.setLength(0); 1096 1097 try { 1098 if (baseTypeDataProvider instanceof CompoundDataProvider) { 1099 /* 1100 * TODO: 1101 */ 1102 /* 1103 * buffer.append(baseTypeDataProvider.getDataValue(obj, columnIndex, rowIndex)); 1104 */ 1105 if (obj instanceof String[]) 1106 buffer.append(Array.get(obj, rowIndex)); 1107 else 1108 buffer.append("*UNSUPPORTED*"); 1109 } 1110 else if (baseTypeDataProvider instanceof ArrayDataProvider) { 1111 buffer.append(baseTypeDataProvider.getDataValue(obj, columnIndex, rowIndex)); 1112 } 1113 else { 1114 buffer.append(baseTypeDataProvider.getDataValue(obj, rowIndex)); 1115 } 1116 1117 theValue = buffer.toString(); 1118 } 1119 catch (Exception ex) { 1120 log.debug("getDataValue({}, {}): failure: ", rowIndex, columnIndex, ex); 1121 theValue = DataFactoryUtils.errStr; 1122 } 1123 1124 log.trace("getDataValue({}, {}, {})=({}): finish", obj, rowIndex, columnIndex, theValue); 1125 1126 return theValue; 1127 } 1128 1129 /* @Override 1130 public Object getDataValue(Object obj, int index) { 1131 throw new UnsupportedOperationException("getDataValue(Object, int) should not be called for VlenDataProviders"); 1132 } */ 1133 1134 @Override 1135 public void setDataValue(int columnIndex, int rowIndex, Object newValue) { 1136 /* 1137 * TODO: 1138 */ 1139 } 1140 1141 @Override 1142 public void setDataValue(int columnIndex, int rowIndex, Object bufObject, Object newValue) { 1143 /* 1144 * TODO: 1145 */ 1146 } 1147 1148 @Override 1149 public void setDataValue(int index, Object bufObject, Object newValue) { 1150 throw new UnsupportedOperationException("setDataValue(int, Object, Object) should not be called for VlenDataProviders"); 1151 } 1152 } 1153 1154 private static class StringDataProvider extends HDFDataProvider 1155 { 1156 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(StringDataProvider.class); 1157 1158 private final long typeSize; 1159 1160 StringDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed) throws Exception { 1161 super(dtype, dataBuf, dataTransposed); 1162 1163 typeSize = dtype.getDatatypeSize(); 1164 } 1165 1166 @Override 1167 public Object getDataValue(Object obj, int index) { 1168 if (obj instanceof byte[]) { 1169 int strlen = (int) typeSize; 1170 1171 log.trace("getDataValue({}, {}): converting byte[] to String", obj, index); 1172 1173 String str = new String((byte[]) obj, index * strlen, strlen); 1174 int idx = str.indexOf('\0'); 1175 if (idx > 0) 1176 str = str.substring(0, idx); 1177 1178 theValue = str.trim(); 1179 } 1180 else 1181 super.getDataValue(obj, index); 1182 1183 log.trace("getDataValue({}, {})=({}): finish", obj, index, theValue); 1184 1185 return theValue; 1186 } 1187 1188 @Override 1189 public void setDataValue(int columnIndex, int rowIndex, Object newValue) { 1190 try { 1191 int bufIndex = physicalLocationToBufIndex(rowIndex, columnIndex); 1192 1193 updateStringBytes(dataBuf, newValue, bufIndex); 1194 } 1195 catch (Exception ex) { 1196 log.debug("setDataValue({}, {}, {}): cell value update failure: ", rowIndex, columnIndex, newValue, ex); 1197 } 1198 log.trace("setDataValue({}, {}, {}): finish", rowIndex, columnIndex, newValue); 1199 } 1200 1201 @Override 1202 public void setDataValue(int index, Object bufObject, Object newValue) { 1203 try { 1204 updateStringBytes(bufObject, newValue, index); 1205 } 1206 catch (Exception ex) { 1207 log.debug("setDataValue({}, {}, {}): cell value update failure: ", index, bufObject, newValue, ex); 1208 } 1209 log.trace("setDataValue({}, {}, {}): finish", index, bufObject, newValue); 1210 } 1211 1212 private void updateStringBytes(Object curBuf, Object newValue, int bufStartIndex) { 1213 if (curBuf instanceof String[]) { 1214 Array.set(curBuf, bufStartIndex, newValue); 1215 } 1216 else if (curBuf instanceof byte[]) { 1217 // Update String using data represented as a byte[] 1218 int strLen = (int) typeSize; 1219 byte[] newValueBytes = ((String) newValue).getBytes(); 1220 byte[] curBytes = (byte[]) curBuf; 1221 int n = Math.min(strLen, newValueBytes.length); 1222 1223 bufStartIndex *= typeSize; 1224 1225 System.arraycopy(newValueBytes, 0, curBytes, bufStartIndex, n); 1226 1227 bufStartIndex += n; 1228 n = strLen - newValueBytes.length; 1229 1230 // space padding 1231 for (int i = 0; i < n; i++) 1232 curBytes[bufStartIndex + i] = ' '; 1233 } 1234 1235 isValueChanged = true; 1236 } 1237 } 1238 1239 private static class CharDataProvider extends HDFDataProvider 1240 { 1241 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CharDataProvider.class); 1242 1243 CharDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed) throws Exception { 1244 super(dtype, dataBuf, dataTransposed); 1245 } 1246 1247 @Override 1248 public Object getDataValue(int columnIndex, int rowIndex) { 1249 /* 1250 * Compatibility with HDF4 8-bit character types that get converted to a String 1251 * ahead of time. 1252 */ 1253 if (dataBuf instanceof String) { 1254 log.trace("getDataValue({}, {})=({}): finish", rowIndex, columnIndex, dataBuf); 1255 return dataBuf; 1256 } 1257 1258 return super.getDataValue(columnIndex, rowIndex); 1259 } 1260 } 1261 1262 private static class NumericalDataProvider extends HDFDataProvider 1263 { 1264 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NumericalDataProvider.class); 1265 1266 private final boolean isUINT64; 1267 1268 private final long typeSize; 1269 1270 NumericalDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed) throws Exception { 1271 super(dtype, dataBuf, dataTransposed); 1272 1273 typeSize = dtype.getDatatypeSize(); 1274 isUINT64 = dtype.isUnsigned() && (typeSize == 8); 1275 } 1276 1277 @Override 1278 public Object getDataValue(int columnIndex, int rowIndex) { 1279 super.getDataValue(columnIndex, rowIndex); 1280 1281 try { 1282 if (isUINT64) 1283 theValue = Tools.convertUINT64toBigInt(Long.valueOf((long) theValue)); 1284 } 1285 catch (Exception ex) { 1286 log.debug("getDataValue({}, {}): failure: ", rowIndex, columnIndex, ex); 1287 theValue = DataFactoryUtils.errStr; 1288 } 1289 1290 log.trace("getDataValue({}, {})=({}): finish", rowIndex, columnIndex, theValue); 1291 1292 return theValue; 1293 } 1294 1295 @Override 1296 public Object getDataValue(Object obj, int index) { 1297 super.getDataValue(obj, index); 1298 1299 try { 1300 if (isUINT64) 1301 theValue = Tools.convertUINT64toBigInt(Long.valueOf((long) theValue)); 1302 } 1303 catch (Exception ex) { 1304 log.debug("getDataValue({}): failure: ", index, ex); 1305 theValue = DataFactoryUtils.errStr; 1306 } 1307 1308 log.trace("getDataValue({})=({}): finish", index, theValue); 1309 1310 return theValue; 1311 } 1312 } 1313 1314 private static class EnumDataProvider extends HDFDataProvider 1315 { 1316 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(EnumDataProvider.class); 1317 1318 EnumDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed) throws Exception { 1319 super(dtype, dataBuf, dataTransposed); 1320 } 1321 } 1322 1323 private static class BitfieldDataProvider extends HDFDataProvider 1324 { 1325 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BitfieldDataProvider.class); 1326 1327 private final long typeSize; 1328 1329 BitfieldDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed) throws Exception { 1330 super(dtype, dataBuf, dataTransposed); 1331 1332 typeSize = dtype.getDatatypeSize(); 1333 } 1334 1335 @Override 1336 public Object getDataValue(int columnIndex, int rowIndex) { 1337 try { 1338 int bufIndex = physicalLocationToBufIndex(rowIndex, columnIndex); 1339 1340 bufIndex *= typeSize; 1341 theValue = populateByteArray(dataBuf, bufIndex); 1342 } 1343 catch (Exception ex) { 1344 log.debug("getDataValue({}, {}): failure: ", rowIndex, columnIndex, ex); 1345 theValue = DataFactoryUtils.errStr; 1346 } 1347 1348 log.trace("getDataValue({}, {})=({}): finish", rowIndex, columnIndex, theValue); 1349 1350 return theValue; 1351 } 1352 1353 @Override 1354 public Object getDataValue(Object obj, int index) { 1355 try { 1356 index *= typeSize; 1357 theValue = populateByteArray(obj, index); 1358 } 1359 catch (Exception ex) { 1360 log.debug("getDataValue({}): ", index, ex); 1361 theValue = DataFactoryUtils.errStr; 1362 } 1363 1364 log.trace("getDataValue({})=({}): finish", index, theValue); 1365 1366 return theValue; 1367 } 1368 1369 private byte[] populateByteArray(Object byteBuf, int startIndex) { 1370 byte[] byteElements = new byte[(int) typeSize]; 1371 1372 for (int i = 0; i < typeSize; i++) 1373 byteElements[i] = Array.getByte(byteBuf, startIndex + i); 1374 1375 return byteElements; 1376 } 1377 } 1378 1379 private static class RefDataProvider extends HDFDataProvider 1380 { 1381 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RefDataProvider.class); 1382 1383 RefDataProvider(final Datatype dtype, final Object dataBuf, final boolean dataTransposed) throws Exception { 1384 super(dtype, dataBuf, dataTransposed); 1385 } 1386 } 1387 1388}