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.text.NumberFormat; 019import java.util.HashMap; 020import java.util.List; 021 022import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; 023import org.eclipse.nebula.widgets.nattable.data.convert.DisplayConverter; 024import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; 025 026import hdf.hdf5lib.exceptions.HDF5Exception; 027import hdf.object.CompoundDataFormat; 028import hdf.object.DataFormat; 029import hdf.object.Datatype; 030import hdf.object.h5.H5Datatype; 031import hdf.view.Tools; 032 033/** 034 * A Factory class to return a concrete class implementing the IDisplayConverter 035 * interface in order to convert data values into human-readable forms in a NatTable. 036 * The returned class is also responsible for converting the human-readable form back 037 * into real data when writing the data object back to the file. 038 * 039 * @author Jordan T. Henderson 040 * @version 1.0 2/9/2019 041 * 042 */ 043public class DataDisplayConverterFactory { 044 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DataDisplayConverterFactory.class); 045 046 /* 047 * To keep things clean from an API perspective, keep a static reference to the last 048 * CompoundDataFormat that was passed in. This keeps us from needing to pass the 049 * CompoundDataFormat object as a parameter to every DataDisplayConverter class, 050 * since it's really only needed by the CompoundDataDisplayConverter. 051 */ 052 private static DataFormat dataFormatReference = null; 053 054 public static HDFDisplayConverter getDataDisplayConverter(final DataFormat dataObject) throws Exception { 055 if (dataObject == null) { 056 log.debug("getDataDisplayConverter(DataFormat): data object is null"); 057 return null; 058 } 059 060 dataFormatReference = dataObject; 061 062 HDFDisplayConverter converter = getDataDisplayConverter(dataObject.getDatatype()); 063 064 return converter; 065 } 066 067 private static final HDFDisplayConverter getDataDisplayConverter(final Datatype dtype) throws Exception { 068 HDFDisplayConverter converter = null; 069 070 try { 071 if (dtype.isCompound()) 072 converter = new CompoundDataDisplayConverter(dtype); 073 else if (dtype.isArray()) 074 converter = new ArrayDataDisplayConverter(dtype); 075 else if (dtype.isVLEN() && !dtype.isVarStr()) 076 converter = new VlenDataDisplayConverter(dtype); 077 else if (dtype.isString() || dtype.isVarStr()) 078 converter = new StringDataDisplayConverter(dtype); 079 else if (dtype.isChar()) 080 converter = new CharDataDisplayConverter(dtype); 081 else if (dtype.isInteger() || dtype.isFloat()) 082 converter = new NumericalDataDisplayConverter(dtype); 083 else if (dtype.isEnum()) 084 converter = new EnumDataDisplayConverter(dtype); 085 else if (dtype.isOpaque() || dtype.isBitField()) 086 converter = new BitfieldDataDisplayConverter(dtype); 087 else if (dtype.isRef()) 088 converter = new RefDataDisplayConverter(dtype); 089 } 090 catch (Exception ex) { 091 log.debug("getDataDisplayConverter(Datatype): error occurred in retrieving a DataDisplayConverter: ", ex); 092 converter = null; 093 } 094 095 /* 096 * Try to use a default converter. 097 */ 098 if (converter == null) { 099 log.debug("getDataDisplayConverter(Datatype): using a default data display converter"); 100 101 converter = new HDFDisplayConverter(dtype); 102 } 103 104 return converter; 105 } 106 107 public static class HDFDisplayConverter extends DisplayConverter { 108 protected org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(HDFDisplayConverter.class); 109 protected NumberFormat numberFormat = null; 110 protected boolean showAsHex = false; 111 protected boolean showAsBin = false; 112 protected boolean isEnumConverted = false; 113 114 /* 115 * This field is only used for CompoundDataDisplayConverters, but when the 116 * top-level DisplayConverter is a "container" type, such as an 117 * ArrayDataDisplayConverter, we have to set this field and pass it through in 118 * case there is a CompoundDataDisplayConverter at the bottom of the chain. 119 */ 120 protected int cellRowIdx; 121 protected int cellColIdx; 122 123 HDFDisplayConverter(final Datatype dtype) { 124 cellRowIdx = -1; 125 cellColIdx = -1; 126 } 127 128 @Override 129 public Object canonicalToDisplayValue(Object value) { 130 log.trace("canonicalToDisplayValue({}): start", value); 131 132 if (value instanceof String) { 133 return value; 134 } 135 136 if (value == null) { 137 log.debug("canonicalToDisplayValue({}): value is null", value); 138 return DataFactoryUtils.nullStr; 139 } 140 141 return value; 142 } 143 144 @Override 145 public Object displayToCanonicalValue(Object value) { 146 log.trace("displayToCanonicalValue({}): start", value); 147 return value; 148 } 149 150 public void setNumberFormat(NumberFormat format) { 151 numberFormat = format; 152 } 153 154 public void setShowAsHex(boolean asHex) { 155 showAsHex = asHex; 156 } 157 158 public void setShowAsBin(boolean asBin) { 159 showAsBin = asBin; 160 } 161 162 public void setConvertEnum(boolean convert) { 163 isEnumConverted = convert; 164 } 165 166 } 167 168 private static class CompoundDataDisplayConverter extends HDFDisplayConverter { 169 private final HashMap<Integer, Integer> baseConverterIndexMap; 170 private final HashMap<Integer, Integer> relCmpdStartIndexMap; 171 private final HDFDisplayConverter[] memberTypeConverters; 172 private final StringBuilder buffer; 173 private final int nTotFields; 174 175 CompoundDataDisplayConverter(final Datatype dtype) throws Exception { 176 super(dtype); 177 178 log = org.slf4j.LoggerFactory.getLogger(CompoundDataDisplayConverter.class); 179 180 if (!dtype.isCompound()) { 181 log.debug("datatype is not a compound type"); 182 throw new Exception("CompoundDataDisplayConverter: 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 HDFDisplayConverters", localSelectedTypes.size()); 190 191 memberTypeConverters = new HDFDisplayConverter[localSelectedTypes.size()]; 192 for (int i = 0; i < memberTypeConverters.length; i++) { 193 log.trace("retrieving DataDisplayConverter for member {}", i); 194 195 try { 196 memberTypeConverters[i] = getDataDisplayConverter(localSelectedTypes.get(i)); 197 198 /* 199 * Make base datatype converters inherit the data conversion settings. 200 */ 201 memberTypeConverters[i].setShowAsHex(this.showAsHex); 202 memberTypeConverters[i].setShowAsBin(this.showAsBin); 203 memberTypeConverters[i].setNumberFormat(this.numberFormat); 204 memberTypeConverters[i].setConvertEnum(this.isEnumConverted); 205 } 206 catch (Exception ex) { 207 log.debug("failed to retrieve DataDisplayConverter for member {}: ", i, ex); 208 memberTypeConverters[i] = null; 209 } 210 } 211 212 /* 213 * Build necessary index maps. 214 */ 215 HashMap<Integer, Integer>[] maps = DataFactoryUtils.buildIndexMaps(compoundFormat, localSelectedTypes); 216 baseConverterIndexMap = maps[DataFactoryUtils.COL_TO_BASE_CLASS_MAP_INDEX]; 217 relCmpdStartIndexMap = maps[DataFactoryUtils.CMPD_START_IDX_MAP_INDEX]; 218 219 log.trace("index maps built: baseConverterIndexMap = {}, relColIdxMap = {}", 220 baseConverterIndexMap, relCmpdStartIndexMap); 221 222 if (baseConverterIndexMap.size() == 0) { 223 log.debug("base DataDisplayConverter index mapping is invalid - size 0"); 224 throw new Exception("CompoundDataDisplayConverter: invalid DataDisplayConverter mapping of size 0 built"); 225 } 226 227 if (relCmpdStartIndexMap.size() == 0) { 228 log.debug("compound field start index mapping is invalid - size 0"); 229 throw new Exception("CompoundDataDisplayConverter: invalid compound field start index mapping of size 0 built"); 230 } 231 232 nTotFields = baseConverterIndexMap.size(); 233 234 buffer = new StringBuilder(); 235 } 236 237 @Override 238 public Object canonicalToDisplayValue(ILayerCell cell, IConfigRegistry configRegistry, Object value) { 239 cellRowIdx = cell.getRowIndex(); 240 cellColIdx = cell.getColumnIndex() % nTotFields; 241 return canonicalToDisplayValue(value); 242 } 243 244 @Override 245 public Object canonicalToDisplayValue(Object value) { 246 log.trace("canonicalToDisplayValue({}): start", value); 247 248 if (value instanceof String) { 249 return value; 250 } 251 252 if (value == null) { 253 log.debug("canonicalToDisplayValue({}): value is null", value); 254 return DataFactoryUtils.nullStr; 255 } 256 257 buffer.setLength(0); // clear the old string 258 259 try { 260 if (cellColIdx >= nTotFields) 261 cellColIdx %= nTotFields; 262 263 if (value instanceof List) { 264 /* 265 * For Arrays of Compounds, we convert an entire list of data. 266 */ 267 List<?> cmpdList = (List<?>) value; 268 269 buffer.append("{"); 270 for (int i = 0; i < memberTypeConverters.length; i++) { 271 if (i > 0) buffer.append(", "); 272 273 Object curObject = cmpdList.get(i); 274 if (curObject instanceof List) 275 buffer.append(memberTypeConverters[i].canonicalToDisplayValue(curObject)); 276 else { 277 Object dataArrayValue = Array.get(curObject, cellRowIdx); 278 buffer.append(memberTypeConverters[i].canonicalToDisplayValue(dataArrayValue)); 279 } 280 } 281 buffer.append("}"); 282 } 283 else { 284 HDFDisplayConverter converter = memberTypeConverters[baseConverterIndexMap.get(cellColIdx)]; 285 converter.cellRowIdx = cellRowIdx; 286 converter.cellColIdx = cellColIdx - relCmpdStartIndexMap.get(cellColIdx); 287 288 buffer.append(converter.canonicalToDisplayValue(value)); 289 } 290 } 291 catch (Exception ex) { 292 log.debug("canonicalToDisplayValue({}): failure: ", value, ex); 293 buffer.setLength(0); 294 buffer.append(DataFactoryUtils.errStr); 295 } 296 297 return buffer; 298 } 299 300 @Override 301 public void setNumberFormat(NumberFormat format) { 302 super.setNumberFormat(format); 303 304 for (int i = 0; i < memberTypeConverters.length; i++) { 305 memberTypeConverters[i].setNumberFormat(format); 306 } 307 } 308 309 @Override 310 public void setShowAsHex(boolean asHex) { 311 super.setShowAsHex(asHex); 312 313 for (int i = 0; i < memberTypeConverters.length; i++) { 314 memberTypeConverters[i].setShowAsHex(asHex); 315 } 316 } 317 318 @Override 319 public void setShowAsBin(boolean asBin) { 320 super.setShowAsBin(asBin); 321 322 for (int i = 0; i < memberTypeConverters.length; i++) { 323 memberTypeConverters[i].setShowAsBin(asBin); 324 } 325 } 326 327 @Override 328 public void setConvertEnum(boolean convert) { 329 super.setConvertEnum(convert); 330 331 for (int i = 0; i < memberTypeConverters.length; i++) { 332 memberTypeConverters[i].setConvertEnum(convert); 333 } 334 } 335 336 } 337 338 private static class ArrayDataDisplayConverter extends HDFDisplayConverter { 339 private final HDFDisplayConverter baseTypeConverter; 340 private final StringBuilder buffer; 341 342 ArrayDataDisplayConverter(final Datatype dtype) throws Exception { 343 super(dtype); 344 345 log = org.slf4j.LoggerFactory.getLogger(ArrayDataDisplayConverter.class); 346 347 if (!dtype.isArray()) { 348 log.debug("exit: datatype is not an array type"); 349 throw new Exception("ArrayDataDisplayConverter: datatype is not an array type"); 350 } 351 352 Datatype baseType = dtype.getDatatypeBase(); 353 354 if (baseType == null) { 355 log.debug("exit: base datatype is null"); 356 throw new Exception("ArrayDataDisplayConverter: base datatype is null"); 357 } 358 359 try { 360 baseTypeConverter = getDataDisplayConverter(baseType); 361 362 /* 363 * Make base datatype converter inherit the data conversion settings. 364 */ 365 baseTypeConverter.setShowAsHex(this.showAsHex); 366 baseTypeConverter.setShowAsBin(this.showAsBin); 367 baseTypeConverter.setNumberFormat(this.numberFormat); 368 baseTypeConverter.setConvertEnum(this.isEnumConverted); 369 } 370 catch (Exception ex) { 371 log.debug("exit: couldn't get DataDisplayConverter for base datatype: ", ex); 372 throw new Exception("ArrayDataDisplayConverter: couldn't get DataDisplayConverter for base datatype: " + ex.getMessage()); 373 } 374 375 buffer = new StringBuilder(); 376 } 377 378 @Override 379 public Object canonicalToDisplayValue(ILayerCell cell, IConfigRegistry configRegistry, Object value) { 380 cellRowIdx = cell.getRowIndex(); 381 cellColIdx = cell.getColumnIndex(); 382 return canonicalToDisplayValue(value); 383 } 384 385 @Override 386 public Object canonicalToDisplayValue(Object value) { 387 log.trace("canonicalToDisplayValue({}): start", value); 388 389 if (value instanceof String) { 390 return value; 391 } 392 393 if (value == null) { 394 log.debug("canonicalToDisplayValue({}): value is null", value); 395 return DataFactoryUtils.nullStr; 396 } 397 398 buffer.setLength(0); // clear the old string 399 400 /* 401 * Pass the cell's row and column index down in case there is a 402 * CompoundDataDisplayConverter at the bottom of the chain. 403 */ 404 baseTypeConverter.cellRowIdx = cellRowIdx; 405 baseTypeConverter.cellColIdx = cellColIdx; 406 407 try { 408 Object obj; 409 Object convertedValue; 410 int arrLen = Array.getLength(value); 411 412 log.trace("canonicalToDisplayValue({}): array length={}", value, arrLen); 413 414 if (!(baseTypeConverter instanceof CompoundDataDisplayConverter)) 415 buffer.append("["); 416 417 for (int i = 0; i < arrLen; i++) { 418 if (i > 0) buffer.append(", "); 419 420 obj = Array.get(value, i); 421 422 convertedValue = baseTypeConverter.canonicalToDisplayValue(obj); 423 424 buffer.append(convertedValue); 425 } 426 427 if (!(baseTypeConverter instanceof CompoundDataDisplayConverter)) 428 buffer.append("]"); 429 } 430 catch (Exception ex) { 431 log.debug("canonicalToDisplayValue({}): failure: ", value, ex); 432 buffer.setLength(0); 433 buffer.append(DataFactoryUtils.errStr); 434 } 435 436 return buffer; 437 } 438 439 @Override 440 public void setNumberFormat(NumberFormat format) { 441 super.setNumberFormat(format); 442 443 baseTypeConverter.setNumberFormat(format); 444 } 445 446 @Override 447 public void setShowAsHex(boolean asHex) { 448 super.setShowAsHex(asHex); 449 450 baseTypeConverter.setShowAsHex(asHex); 451 } 452 453 @Override 454 public void setShowAsBin(boolean asBin) { 455 super.setShowAsBin(asBin); 456 457 baseTypeConverter.setShowAsBin(asBin); 458 } 459 460 @Override 461 public void setConvertEnum(boolean convert) { 462 super.setConvertEnum(convert); 463 464 baseTypeConverter.setConvertEnum(convert); 465 } 466 467 } 468 469 private static class VlenDataDisplayConverter extends HDFDisplayConverter { 470 private final HDFDisplayConverter baseTypeConverter; 471 472 VlenDataDisplayConverter(final Datatype dtype) throws Exception { 473 super(dtype); 474 475 log = org.slf4j.LoggerFactory.getLogger(VlenDataDisplayConverter.class); 476 477 if (!dtype.isVLEN() || dtype.isVarStr()) { 478 log.debug("exit: datatype is not a variable-length type or is a variable-length string type (use StringDataDisplayConverter)"); 479 throw new Exception("VlenDataDisplayConverter: datatype is not a variable-length type or is a variable-length string type (use StringDataDisplayConverter)"); 480 } 481 482 Datatype baseType = dtype.getDatatypeBase(); 483 484 if (baseType == null) { 485 log.debug("base datatype is null"); 486 throw new Exception("VlenDataDisplayConverter: base datatype is null"); 487 } 488 489 try { 490 baseTypeConverter = getDataDisplayConverter(baseType); 491 492 /* 493 * Make base datatype converter inherit the data conversion settings. 494 */ 495 baseTypeConverter.setShowAsHex(this.showAsHex); 496 baseTypeConverter.setShowAsBin(this.showAsBin); 497 baseTypeConverter.setNumberFormat(this.numberFormat); 498 baseTypeConverter.setConvertEnum(this.isEnumConverted); 499 } 500 catch (Exception ex) { 501 log.debug("couldn't get DataDisplayConverter for base datatype: ", ex); 502 throw new Exception("VlenDataDisplayConverter: couldn't get DataDisplayConverter for base datatype: " + ex.getMessage()); 503 } 504 } 505 506 @Override 507 public void setNumberFormat(NumberFormat format) { 508 super.setNumberFormat(format); 509 510 baseTypeConverter.setNumberFormat(format); 511 } 512 513 @Override 514 public void setShowAsHex(boolean asHex) { 515 super.setShowAsHex(asHex); 516 517 baseTypeConverter.setShowAsHex(asHex); 518 } 519 520 @Override 521 public void setShowAsBin(boolean asBin) { 522 super.setShowAsBin(asBin); 523 524 baseTypeConverter.setShowAsBin(asBin); 525 } 526 527 @Override 528 public void setConvertEnum(boolean convert) { 529 super.setConvertEnum(convert); 530 531 baseTypeConverter.setConvertEnum(convert); 532 } 533 534 } 535 536 private static class StringDataDisplayConverter extends HDFDisplayConverter { 537 StringDataDisplayConverter(final Datatype dtype) throws Exception { 538 super(dtype); 539 540 log = org.slf4j.LoggerFactory.getLogger(StringDataDisplayConverter.class); 541 542 if (!dtype.isString() && !dtype.isVarStr()) { 543 log.debug("datatype is not a string type"); 544 throw new Exception("StringDataDisplayConverter: datatype is not a string type"); 545 } 546 } 547 548 } 549 550 private static class CharDataDisplayConverter extends HDFDisplayConverter { 551 CharDataDisplayConverter(final Datatype dtype) throws Exception { 552 super(dtype); 553 554 log = org.slf4j.LoggerFactory.getLogger(CharDataDisplayConverter.class); 555 556 if (!dtype.isChar()) { 557 log.debug("datatype is not a character type"); 558 throw new Exception("CharDataDisplayConverter: datatype is not a character type"); 559 } 560 } 561 562 @Override 563 public Object displayToCanonicalValue(Object value) { 564 char charValue = ((String) value).charAt(0); 565 return (int) charValue; 566 } 567 } 568 569 private static class NumericalDataDisplayConverter extends HDFDisplayConverter { 570 private final StringBuilder buffer; 571 private final long typeSize; 572 private final boolean isUINT64; 573 574 NumericalDataDisplayConverter(final Datatype dtype) throws Exception { 575 super(dtype); 576 577 log = org.slf4j.LoggerFactory.getLogger(NumericalDataDisplayConverter.class); 578 579 if (!dtype.isInteger() && !dtype.isFloat()) { 580 log.debug("datatype is not an integer or floating-point type"); 581 throw new Exception("NumericalDataDisplayConverter: datatype is not an integer or floating-point type"); 582 } 583 584 buffer = new StringBuilder(); 585 586 typeSize = dtype.getDatatypeSize(); 587 isUINT64 = dtype.isUnsigned() && (typeSize == 8); 588 } 589 590 @Override 591 public Object canonicalToDisplayValue(Object value) { 592 log.trace("canonicalToDisplayValue({}): start", value); 593 594 if (value instanceof String) { 595 return value; 596 } 597 598 if (value == null) { 599 log.debug("canonicalToDisplayValue({}): value is null", value); 600 return DataFactoryUtils.nullStr; 601 } 602 603 buffer.setLength(0); // clear the old string 604 605 try { 606 if (showAsHex) { 607 if (isUINT64) { 608 buffer.append(Tools.toHexString((BigInteger) value, 8)); 609 } 610 else { 611 buffer.append(Tools.toHexString(Long.valueOf(value.toString()), (int) typeSize)); 612 } 613 } 614 else if (showAsBin) { 615 if (isUINT64) { 616 buffer.append(Tools.toBinaryString((BigInteger) value, 8)); 617 } 618 else { 619 buffer.append(Tools.toBinaryString(Long.valueOf(value.toString()), (int) typeSize)); 620 } 621 } 622 else if (numberFormat != null) { 623 buffer.append(numberFormat.format(value)); 624 } 625 else { 626 buffer.append(value.toString()); 627 } 628 } 629 catch (Exception ex) { 630 log.debug("canonicalToDisplayValue({}): failure: ", value, ex); 631 buffer.setLength(0); 632 buffer.append(DataFactoryUtils.errStr); 633 } 634 635 return buffer; 636 } 637 638 } 639 640 private static class EnumDataDisplayConverter extends HDFDisplayConverter { 641 private final StringBuilder buffer; 642 private final H5Datatype enumType; 643 644 EnumDataDisplayConverter(final Datatype dtype) throws Exception { 645 super(dtype); 646 647 log = org.slf4j.LoggerFactory.getLogger(EnumDataDisplayConverter.class); 648 649 if (!dtype.isEnum()) { 650 log.debug("datatype is not an enum type"); 651 throw new Exception("EnumDataDisplayConverter: datatype is not an enum type"); 652 } 653 654 buffer = new StringBuilder(); 655 656 enumType = (H5Datatype) dtype; 657 } 658 659 @Override 660 public Object canonicalToDisplayValue(Object value) { 661 log.trace("canonicalToDisplayValue({}): start", value); 662 663 if (value instanceof String) { 664 return value; 665 } 666 667 if (value == null) { 668 log.debug("canonicalToDisplayValue({}): value is null", value); 669 return DataFactoryUtils.nullStr; 670 } 671 672 buffer.setLength(0); // clear the old string 673 674 try { 675 if (isEnumConverted) { 676 String[] retValues = null; 677 678 try { 679 retValues = enumType.convertEnumValueToName(value); 680 } 681 catch (HDF5Exception ex) { 682 log.trace("canonicalToDisplayValue({}): Could not convert enum values to names: ", value, ex); 683 retValues = null; 684 } 685 686 if (retValues != null) 687 buffer.append(retValues[0]); 688 else 689 buffer.append(DataFactoryUtils.nullStr); 690 } 691 else 692 buffer.append(value); 693 } 694 catch (Exception ex) { 695 log.debug("canonicalToDisplayValue({}): failure: ", value, ex); 696 buffer.setLength(0); 697 buffer.append(DataFactoryUtils.errStr); 698 } 699 700 return buffer; 701 } 702 703 } 704 705 private static class BitfieldDataDisplayConverter extends HDFDisplayConverter { 706 private final StringBuilder buffer; 707 private final boolean isOpaque; 708 709 BitfieldDataDisplayConverter(final Datatype dtype) throws Exception { 710 super(dtype); 711 712 log = org.slf4j.LoggerFactory.getLogger(BitfieldDataDisplayConverter.class); 713 714 if (!dtype.isBitField() && !dtype.isOpaque()) { 715 log.debug("datatype is not a bitfield or opaque type"); 716 throw new Exception("BitfieldDataDisplayConverter: datatype is not a bitfield or opaque type"); 717 } 718 719 buffer = new StringBuilder(); 720 721 isOpaque = dtype.isOpaque(); 722 } 723 724 @Override 725 public Object canonicalToDisplayValue(Object value) { 726 log.trace("canonicalToDisplayValue({}): start", value); 727 728 if (value instanceof String) { 729 return value; 730 } 731 732 if (value == null) { 733 log.debug("canonicalToDisplayValue({}): value is null", value); 734 return DataFactoryUtils.nullStr; 735 } 736 737 buffer.setLength(0); // clear the old string 738 739 try { 740 for (int i = 0; i < ((byte[]) value).length; i++) { 741 if (i > 0) { 742 buffer.append(isOpaque ? " " : ":"); 743 } 744 745 buffer.append(Tools.toHexString((((byte[]) value)[i]), 1)); 746 } 747 } 748 catch (Exception ex) { 749 log.debug("canonicalToDisplayValue({}): failure: ", value, ex); 750 buffer.setLength(0); 751 buffer.append(DataFactoryUtils.errStr); 752 } 753 754 return buffer; 755 } 756 757 } 758 759 private static class RefDataDisplayConverter extends HDFDisplayConverter { 760 RefDataDisplayConverter(final Datatype dtype) throws Exception { 761 super(dtype); 762 763 log = org.slf4j.LoggerFactory.getLogger(RefDataDisplayConverter.class); 764 765 if (!dtype.isRef()) { 766 log.debug("datatype is not a reference type"); 767 throw new Exception("RefDataDisplayConverter: datatype is not a reference type"); 768 } 769 } 770 } 771 772}