001 /* 002 * Copyright (c) 2007-2014 Concurrent, Inc. All Rights Reserved. 003 * 004 * Project and contact information: http://www.cascading.org/ 005 * 006 * This file is part of the Cascading project. 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020 021 package cascading.tuple; 022 023 import java.beans.ConstructorProperties; 024 import java.lang.reflect.Type; 025 import java.util.Arrays; 026 import java.util.Iterator; 027 028 import cascading.tuple.coerce.Coercions; 029 import cascading.tuple.type.CoercibleType; 030 import cascading.util.ForeverValueIterator; 031 import org.slf4j.Logger; 032 import org.slf4j.LoggerFactory; 033 034 /** 035 * Class TupleEntry allows a {@link Tuple} instance and its declaring {@link Fields} instance to be used as a single object. 036 * <p/> 037 * Once a TupleEntry is created, its Fields cannot be changed, but the Tuple instance it holds can be replaced or 038 * modified. The managed Tuple should not have elements added or removed, as this will break the relationship with 039 * the associated Fields instance. 040 * <p/> 041 * If type information is provided on the Fields instance, all setters on this class will use that information to 042 * coerce the given object to the expected type. 043 * <p/> 044 * For example, if position is is of type {@code long}, then {@code entry.setString(0, "9" )} will coerce the "9" to a 045 * long {@code 9}. Thus, {@code entry.getObject(0) == 9l}. 046 * <p/> 047 * No coercion is performed with the {@link #getObject(Comparable)} and {@link #getObject(int)} methods. 048 * <p/> 049 * To set a value without coercion, see the {@link #setRaw(Comparable, Object)} and {@link #setRaw(int, Object)} 050 * methods. 051 * 052 * @see Fields 053 * @see Tuple 054 */ 055 public class TupleEntry 056 { 057 private static final Logger LOG = LoggerFactory.getLogger( TupleEntry.class ); 058 059 private static final CoercibleType[] EMPTY_COERCIONS = new CoercibleType[ 0 ]; 060 private static final ForeverValueIterator<CoercibleType> OBJECT_ITERATOR = new ForeverValueIterator<CoercibleType>( Coercions.OBJECT ); 061 062 /** An EMPTY TupleEntry instance for use as a stand in instead of a {@code null}. */ 063 public static final TupleEntry NULL = new TupleEntry( Fields.NONE, Tuple.NULL ); 064 065 /** Field fields */ 066 private Fields fields; 067 068 private CoercibleType[] coercions = EMPTY_COERCIONS; 069 070 /** Field isUnmodifiable */ 071 private boolean isUnmodifiable = false; 072 /** Field tuple */ 073 Tuple tuple; 074 075 /** 076 * Method select will select a new Tuple instance from the given set of entries. Entries order is significant to 077 * the selector. 078 * 079 * @param selector of type Fields 080 * @param entries of type TupleEntry 081 * @return Tuple 082 */ 083 public static Tuple select( Fields selector, TupleEntry... entries ) 084 { 085 // todo: consider just appending tuples values and just peeking those values 086 Tuple result = null; 087 088 // does not do field checks 089 if( selector.isAll() ) 090 { 091 for( TupleEntry entry : entries ) 092 { 093 if( result == null ) 094 result = entry.getTuple(); 095 else 096 result = result.append( entry.getTuple() ); 097 } 098 099 return result; 100 } 101 102 int size = 0; 103 104 for( TupleEntry entry : entries ) 105 size += entry.size(); 106 107 result = Tuple.size( selector.size() ); 108 109 int offset = 0; 110 111 for( TupleEntry entry : entries ) 112 { 113 for( int i = 0; i < selector.size(); i++ ) 114 { 115 Comparable field = selector.get( i ); 116 117 int pos; 118 119 if( field instanceof String ) 120 { 121 pos = entry.fields.indexOfSafe( field ); 122 123 if( pos == -1 ) 124 continue; 125 } 126 else 127 { 128 pos = entry.fields.translatePos( (Integer) field, size ) - offset; 129 130 if( pos >= entry.size() || pos < 0 ) 131 continue; 132 } 133 134 result.set( i, entry.getObject( pos ) ); // last in wins 135 } 136 137 offset += entry.size(); 138 } 139 140 return result; 141 } 142 143 /** Constructor TupleEntry creates a new TupleEntry instance. */ 144 public TupleEntry() 145 { 146 this.fields = Fields.NONE; 147 148 setCoercions(); 149 } 150 151 /** 152 * Constructor TupleEntry creates a new TupleEntry instance. 153 * 154 * @param isUnmodifiable of type boolean 155 */ 156 @ConstructorProperties({"isUnmodifiable"}) 157 public TupleEntry( boolean isUnmodifiable ) 158 { 159 this.fields = Fields.NONE; 160 this.isUnmodifiable = isUnmodifiable; 161 162 setCoercions(); 163 } 164 165 /** 166 * Constructor TupleEntry creates a new TupleEntry instance. 167 * 168 * @param fields of type Fields 169 */ 170 @ConstructorProperties({"fields"}) 171 public TupleEntry( Fields fields ) 172 { 173 this.fields = fields; 174 175 setCoercions(); 176 } 177 178 /** 179 * Constructor TupleEntry creates a new TupleEntry instance. 180 * 181 * @param fields of type Fields 182 * @param isUnmodifiable of type boolean 183 */ 184 @ConstructorProperties({"fields", "isUnmodifiable"}) 185 public TupleEntry( Fields fields, boolean isUnmodifiable ) 186 { 187 this.fields = fields; 188 this.isUnmodifiable = isUnmodifiable; 189 190 setCoercions(); 191 } 192 193 /** 194 * Constructor TupleEntry creates a new TupleEntry instance. 195 * 196 * @param fields of type Fields 197 * @param tuple of type Tuple 198 * @param isUnmodifiable of type boolean 199 */ 200 @ConstructorProperties({"fields", "tuple", "isUnmodifiable"}) 201 public TupleEntry( Fields fields, Tuple tuple, boolean isUnmodifiable ) 202 { 203 this.fields = fields; 204 this.isUnmodifiable = isUnmodifiable; 205 setTuple( tuple ); 206 207 setCoercions(); 208 } 209 210 /** 211 * Constructor TupleEntry creates a new TupleEntry instance. 212 * 213 * @param fields of type Fields 214 * @param tuple of type Tuple 215 */ 216 @ConstructorProperties({"fields", "tuple"}) 217 public TupleEntry( Fields fields, Tuple tuple ) 218 { 219 this.fields = fields; 220 this.tuple = tuple; 221 222 setCoercions(); 223 } 224 225 /** 226 * Constructor TupleEntry creates a new TupleEntry instance that is a safe copy of the given tupleEntry. 227 * <p/> 228 * The new instance is safe to cache and will be modifiable regardless of the given tupleEntry state. 229 * 230 * @param tupleEntry of type TupleEntry 231 */ 232 @ConstructorProperties({"tupleEntry"}) 233 public TupleEntry( TupleEntry tupleEntry ) 234 { 235 this.fields = tupleEntry.getFields(); 236 this.tuple = tupleEntry.getTupleCopy(); 237 238 setCoercions(); 239 } 240 241 /** 242 * Constructor TupleEntry creates a new TupleEntry instance. 243 * 244 * @param tuple of type Tuple 245 */ 246 @ConstructorProperties({"tuple"}) 247 public TupleEntry( Tuple tuple ) 248 { 249 this.fields = Fields.size( tuple.size() ); 250 this.tuple = tuple; 251 252 setCoercions(); 253 } 254 255 private void setCoercions() 256 { 257 if( coercions != EMPTY_COERCIONS ) 258 return; 259 260 Fields fields = getFields(); 261 Type[] types = fields.types; // safe to not get a copy 262 int size = fields.size(); 263 264 size = size == 0 && tuple != null ? tuple.size() : size; 265 266 if( coercions.length < size ) 267 coercions = Coercions.coercibleArray( size, types ); 268 } 269 270 /** 271 * Method isUnmodifiable returns true if this TupleEntry is unmodifiable. 272 * 273 * @return boolean 274 */ 275 public boolean isUnmodifiable() 276 { 277 return isUnmodifiable; 278 } 279 280 /** 281 * Method getFields returns the fields of this TupleEntry object. 282 * 283 * @return the fields (type Fields) of this TupleEntry object. 284 */ 285 public Fields getFields() 286 { 287 return fields; 288 } 289 290 /** 291 * Returns true if there are types associated with this instance. 292 * 293 * @return boolean 294 */ 295 public boolean hasTypes() 296 { 297 return fields.hasTypes(); 298 } 299 300 /** 301 * Method getTuple returns the tuple of this TupleEntry object. 302 * 303 * @return the tuple (type Tuple) of this TupleEntry object. 304 */ 305 public Tuple getTuple() 306 { 307 return tuple; 308 } 309 310 /** 311 * Method getTupleCopy returns a copy of the tuple of this TupleEntry object. 312 * 313 * @return a copy of the tuple (type Tuple) of this TupleEntry object. 314 */ 315 public Tuple getTupleCopy() 316 { 317 return new Tuple( tuple ); 318 } 319 320 /** 321 * Method getCoercedTuple is a helper method for copying the current tuple elements into a new Tuple, 322 * of the same size, as the requested coerced types. 323 * 324 * @param types of type Type[] 325 * @return returns the a new Tuple instance with coerced values 326 */ 327 public Tuple getCoercedTuple( Type[] types ) 328 { 329 return getCoercedTuple( types, Tuple.size( types.length ) ); 330 } 331 332 /** 333 * Method getCoercedTuple is a helper method for copying the current tuple elements into the new Tuple, 334 * of the same size, as the requested coerced types. 335 * 336 * @param types of type Type[] 337 * @param into of type Tuple 338 * @return returns the given into Tuple instance with coerced values 339 */ 340 public Tuple getCoercedTuple( Type[] types, Tuple into ) 341 { 342 if( coercions.length != types.length || types.length != into.size() ) 343 throw new IllegalArgumentException( "current entry and given tuple and types must be same length" ); 344 345 for( int i = 0; i < coercions.length; i++ ) 346 { 347 Object element = tuple.getObject( i ); 348 into.set( i, Coercions.coerce( coercions[ i ], element, types[ i ] ) ); 349 } 350 351 return into; 352 } 353 354 /** 355 * Method setTuple sets the tuple of this TupleEntry object, no copy will be performed. 356 * <p/> 357 * If the given tuple is "unmodifiable" ({@code Tuple.isUnmodifiable() == true}) and this TupleEntry is 358 * not "unmodifiable", a warning will be issued. 359 * <p/> 360 * Unmodifiable tuples are generally owned by the system and cannot be be changed and must not be cached. 361 * 362 * @param tuple the tuple of this TupleEntry object. 363 */ 364 public void setTuple( Tuple tuple ) 365 { 366 if( !isUnmodifiable && tuple.isUnmodifiable() ) 367 throw new IllegalArgumentException( "current entry is modifiable but given tuple is not modifiable, make copy of given Tuple first" ); 368 369 if( tuple != null && isUnmodifiable ) 370 this.tuple = Tuples.asUnmodifiable( tuple ); 371 else 372 this.tuple = tuple; 373 374 setCoercions(); 375 } 376 377 /** 378 * Method setCanonicalTuple replaces each value of the current tuple with the given tuple elements after 379 * they are coerced. 380 * <p/> 381 * This method will modify the existing Tuple wrapped by this TupleEntry instance even 382 * if it is marked as unmodifiable. 383 * 384 * @param tuple to replace the current wrapped Tuple instance 385 */ 386 public void setCanonicalTuple( Tuple tuple ) 387 { 388 if( isUnmodifiable ) 389 tuple = Tuples.asUnmodifiable( tuple ); 390 391 if( fields.size() != tuple.size() ) 392 throw new IllegalArgumentException( "current entry and given tuple must be same length" ); 393 394 for( int i = 0; i < coercions.length; i++ ) 395 { 396 Object element = tuple.getObject( i ); 397 398 this.tuple.set( i, coercions[ i ].canonical( element ) ); // force read type to the expected type 399 } 400 } 401 402 /** 403 * Method setCanonicalValues replaces each value of the current tuple with th give Object[] 404 * after they are coerced. 405 * 406 * @param values to replace the current wrapped tuple instance values 407 */ 408 public void setCanonicalValues( Object[] values ) 409 { 410 if( fields.size() != values.length ) 411 throw new IllegalArgumentException( "current entry and given array must be same length" ); 412 413 for( int i = 0; i < coercions.length; i++ ) 414 { 415 Object element = values[ i ]; 416 417 this.tuple.set( i, coercions[ i ].canonical( element ) ); // force read type to the expected type 418 } 419 } 420 421 /** 422 * Method size returns the number of values in this instance. 423 * 424 * @return int 425 */ 426 public int size() 427 { 428 return tuple.size(); 429 } 430 431 /** 432 * Method get returns the value in the given position pos. 433 * <p/> 434 * This method is deprecated, use {@link #getObject(int)} instead. 435 * 436 * @param pos position of the element to return. 437 * @return Comparable 438 */ 439 @Deprecated 440 public Comparable get( int pos ) 441 { 442 return tuple.get( pos ); 443 } 444 445 /** 446 * Method getObject returns the value in the given position pos. 447 * <p/> 448 * No coercion is performed if there is an associated coercible type. 449 * 450 * @param pos position of the element to return. 451 * @return Object 452 */ 453 public Object getObject( int pos ) 454 { 455 return tuple.getObject( pos ); 456 } 457 458 /** 459 * Method getObject returns the value in the given field or position as the requested type. 460 * <p/> 461 * Coercion is performed to the given type. 462 * 463 * @param pos position of the element to return. 464 * @return Object 465 */ 466 public Object getObject( int pos, Type type ) 467 { 468 return Coercions.coerce( coercions[ pos ], tuple.getObject( pos ), type ); 469 } 470 471 /** 472 * Method get returns the value in the given field or position. 473 * <br/> 474 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 475 * be considered. 476 * <p/> 477 * This method is deprecated, use {@link #getObject(Comparable)} instead. 478 * 479 * @param fieldName field name or position to return 480 * @return Comparable 481 */ 482 @Deprecated 483 public Comparable get( Comparable fieldName ) 484 { 485 return tuple.get( fields.getPos( asFieldName( fieldName ) ) ); 486 } 487 488 /** 489 * Method getObject returns the value in the given field or position. 490 * <br/> 491 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 492 * be considered. 493 * <p/> 494 * No coercion is performed if there is an associated coercible type. 495 * 496 * @param fieldName field name or position to return 497 * @return Comparable 498 */ 499 public Object getObject( Comparable fieldName ) 500 { 501 int pos = fields.getPos( asFieldName( fieldName ) ); 502 return tuple.getObject( pos ); 503 } 504 505 /** 506 * Method getObject returns the value in the given field or position as the requested type. 507 * <br/> 508 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 509 * be considered. 510 * <p/> 511 * Coercion is performed to the given type. 512 * 513 * @param fieldName field name or position to return 514 * @return Comparable 515 */ 516 public Object getObject( Comparable fieldName, Type type ) 517 { 518 int pos = fields.getPos( asFieldName( fieldName ) ); 519 return Coercions.coerce( coercions[ pos ], tuple.getObject( pos ), type ); 520 } 521 522 /** 523 * Method set sets the value in the given field or position. 524 * <p/> 525 * This method is deprecated in favor of {@link #setRaw(Comparable, Object)} 526 * 527 * @param fieldName field name or position to set 528 * @param value of type Comparable 529 */ 530 @Deprecated 531 public void set( Comparable fieldName, Object value ) 532 { 533 tuple.set( fields.getPos( asFieldName( fieldName ) ), value ); 534 } 535 536 /** 537 * Method set sets the value in the given position. 538 * <p/> 539 * No coercion is performed if there is an associated coercible type. 540 * 541 * @param pos position to set 542 * @param value of type Comparable 543 */ 544 public void setRaw( int pos, Object value ) 545 { 546 tuple.set( pos, value ); 547 } 548 549 /** 550 * Method set sets the value in the given field or position. 551 * <p/> 552 * No coercion is performed if there is an associated coercible type. 553 * 554 * @param fieldName field name or position to set 555 * @param value of type Comparable 556 */ 557 public void setRaw( Comparable fieldName, Object value ) 558 { 559 tuple.set( fields.getPos( asFieldName( fieldName ) ), value ); 560 } 561 562 /** 563 * Method set sets the value in the given field or position. 564 * 565 * @param fieldName field name or position to set 566 * @param value of type Comparable 567 */ 568 public void setObject( Comparable fieldName, Object value ) 569 { 570 int pos = fields.getPos( asFieldName( fieldName ) ); 571 572 tuple.set( pos, coercions[ pos ].canonical( value ) ); 573 } 574 575 /** 576 * Method setBoolean sets the value in the given field or position. 577 * 578 * @param fieldName field name or position to set 579 * @param value of type boolean 580 */ 581 public void setBoolean( Comparable fieldName, boolean value ) 582 { 583 int pos = fields.getPos( asFieldName( fieldName ) ); 584 585 tuple.set( pos, coercions[ pos ].canonical( value ) ); 586 } 587 588 /** 589 * Method setShort sets the value in the given field or position. 590 * 591 * @param fieldName field name or position to set 592 * @param value of type short 593 */ 594 public void setShort( Comparable fieldName, short value ) 595 { 596 int pos = fields.getPos( asFieldName( fieldName ) ); 597 598 tuple.set( pos, coercions[ pos ].canonical( value ) ); 599 } 600 601 /** 602 * Method setInteger sets the value in the given field or position. 603 * 604 * @param fieldName field name or position to set 605 * @param value of type int 606 */ 607 public void setInteger( Comparable fieldName, int value ) 608 { 609 int pos = fields.getPos( asFieldName( fieldName ) ); 610 611 tuple.set( pos, coercions[ pos ].canonical( value ) ); 612 } 613 614 /** 615 * Method setLong sets the value in the given field or position. 616 * 617 * @param fieldName field name or position to set 618 * @param value of type long 619 */ 620 public void setLong( Comparable fieldName, long value ) 621 { 622 int pos = fields.getPos( asFieldName( fieldName ) ); 623 624 tuple.set( pos, coercions[ pos ].canonical( value ) ); 625 } 626 627 /** 628 * Method setFloat sets the value in the given field or position. 629 * 630 * @param fieldName field name or position to set 631 * @param value of type float 632 */ 633 public void setFloat( Comparable fieldName, float value ) 634 { 635 int pos = fields.getPos( asFieldName( fieldName ) ); 636 637 tuple.set( pos, coercions[ pos ].canonical( value ) ); 638 } 639 640 /** 641 * Method setDouble sets the value in the given field or position. 642 * 643 * @param fieldName field name or position to set 644 * @param value of type double 645 */ 646 public void setDouble( Comparable fieldName, double value ) 647 { 648 int pos = fields.getPos( asFieldName( fieldName ) ); 649 650 tuple.set( pos, coercions[ pos ].canonical( value ) ); 651 } 652 653 /** 654 * Method setString sets the value in the given field or position. 655 * 656 * @param fieldName field name or position to set 657 * @param value of type String 658 */ 659 public void setString( Comparable fieldName, String value ) 660 { 661 int pos = fields.getPos( asFieldName( fieldName ) ); 662 tuple.set( pos, coercions[ pos ].canonical( value ) ); 663 } 664 665 /** 666 * Method getString returns the element for the given field name or position as a String. 667 * <br/> 668 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 669 * be considered. 670 * 671 * @param fieldName field name or position to return 672 * @return String 673 */ 674 public String getString( Comparable fieldName ) 675 { 676 return (String) getObject( fieldName, String.class ); 677 } 678 679 /** 680 * Method getFloat returns the element for the given field name or position as a float. Zero if null. 681 * <br/> 682 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 683 * be considered. 684 * 685 * @param fieldName field name or position to return 686 * @return float 687 */ 688 public float getFloat( Comparable fieldName ) 689 { 690 return (Float) getObject( fieldName, float.class ); 691 } 692 693 /** 694 * Method getDouble returns the element for the given field name or position as a double. Zero if null. 695 * <br/> 696 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 697 * be considered. 698 * 699 * @param fieldName field name or position to return 700 * @return double 701 */ 702 public double getDouble( Comparable fieldName ) 703 { 704 return (Double) getObject( fieldName, double.class ); 705 } 706 707 /** 708 * Method getInteger returns the element for the given field name or position as an int. Zero if null. 709 * <br/> 710 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 711 * be considered. 712 * 713 * @param fieldName field name or position to return 714 * @return int 715 */ 716 public int getInteger( Comparable fieldName ) 717 { 718 return (Integer) getObject( fieldName, int.class ); 719 } 720 721 /** 722 * Method getLong returns the element for the given field name or position as a long. Zero if null. 723 * <br/> 724 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 725 * be considered. 726 * 727 * @param fieldName field name or position to return 728 * @return long 729 */ 730 public long getLong( Comparable fieldName ) 731 { 732 return (Long) getObject( fieldName, long.class ); 733 } 734 735 /** 736 * Method getShort returns the element for the given field name or position as a short. Zero if null. 737 * <br/> 738 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 739 * be considered. 740 * 741 * @param fieldName field name or position to return 742 * @return short 743 */ 744 public short getShort( Comparable fieldName ) 745 { 746 return (Short) getObject( fieldName, short.class ); 747 } 748 749 /** 750 * Method getBoolean returns the element for the given field name or position as a boolean. 751 * If the value is (case ignored) the string 'true', a {@code true} value will be returned. {@code false} if null. 752 * <br/> 753 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 754 * be considered. 755 * 756 * @param fieldName field name or position to return 757 * @return boolean 758 */ 759 public boolean getBoolean( Comparable fieldName ) 760 { 761 return (Boolean) getObject( fieldName, boolean.class ); 762 } 763 764 private Comparable asFieldName( Comparable fieldName ) 765 { 766 return Fields.asFieldName( fieldName ); 767 } 768 769 /** 770 * Method selectEntry selects the fields specified in the selector from this instance. If {@link Fields#ALL} or the 771 * same fields as declared are given, {@code this} will be returned. 772 * <p/> 773 * The returned TupleEntry will be either modifiable or unmodifiable, depending on the state of this TupleEntry instance. 774 * <p/> 775 * See {@link #selectEntryCopy(Fields)} to guarantee a copy suitable for modifying or caching/storing in a collection. 776 * <p/> 777 * Note this is a bug fix and change from 2.0 and 2.1. In previous versions the modifiable state was dependent 778 * on the given selector. 779 * 780 * @param selector Fields selector that selects the values to return 781 * @return TupleEntry 782 */ 783 public TupleEntry selectEntry( Fields selector ) 784 { 785 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 786 return this; 787 788 if( selector.isNone() ) 789 return isUnmodifiable ? TupleEntry.NULL : new TupleEntry(); 790 791 return new TupleEntry( Fields.asDeclaration( selector ), tuple.get( this.fields, selector ), isUnmodifiable ); 792 } 793 794 /** 795 * Method selectEntry selects the fields specified in selector from this instance. 796 * <p/> 797 * It is guaranteed to return a new modifiable TupleEntry instance at a cost of copying data. 798 * <p/> 799 * The returned instance is safe to cache. 800 * 801 * @param selector Fields selector that selects the values to return 802 * @return TupleEntry 803 */ 804 public TupleEntry selectEntryCopy( Fields selector ) 805 { 806 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 807 return new TupleEntry( this ); 808 809 if( selector.isNone() ) 810 return new TupleEntry(); 811 812 return new TupleEntry( Fields.asDeclaration( selector ), tuple.get( this.fields, selector ) ); 813 } 814 815 /** 816 * Method selectTuple selects the fields specified in the selector from this instance. If {@link Fields#ALL} or the 817 * same fields as declared are given, {@code this.getTuple()} will be returned. 818 * <p/> 819 * The returned Tuple will be either modifiable or unmodifiable, depending on the state of this TupleEntry instance. 820 * <p/> 821 * See {@link #selectTupleCopy(Fields)} to guarantee a copy suitable for modifying or caching/storing in a collection. 822 * <p/> 823 * Note this is a bug fix and change from 2.0 and 2.1. In previous versions the modifiable state was dependent 824 * on the given selector. 825 * 826 * @param selector Fields selector that selects the values to return 827 * @return Tuple 828 */ 829 public Tuple selectTuple( Fields selector ) 830 { 831 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 832 return this.tuple; 833 834 if( selector.isNone() ) 835 return Tuple.NULL; 836 837 Tuple result = tuple.get( fields, selector ); 838 839 if( isUnmodifiable ) 840 Tuples.asUnmodifiable( result ); 841 842 return result; 843 } 844 845 /** 846 * Method selectTupleCopy selects the fields specified in selector from this instance. 847 * <p/> 848 * It is guaranteed to return a new modifiable Tuple instance at a cost of copying data. 849 * <p/> 850 * The returned instance is safe to cache. 851 * 852 * @param selector Fields selector that selects the values to return 853 * @return Tuple 854 */ 855 public Tuple selectTupleCopy( Fields selector ) 856 { 857 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 858 return new Tuple( this.tuple ); 859 860 if( selector.isNone() ) 861 return new Tuple(); 862 863 return tuple.get( fields, selector ); 864 } 865 866 /** 867 * Method selectInto selects the fields specified in the selector from this instance and copies 868 * them into the given tuple argument. 869 * 870 * @param selector of type Fields 871 * @param tuple of type Tuple 872 * @return returns the given tuple argument with new values added 873 */ 874 public Tuple selectInto( Fields selector, Tuple tuple ) 875 { 876 if( selector.isNone() ) 877 return tuple; 878 879 int[] pos = this.tuple.getPos( fields, selector ); 880 881 if( pos == null || pos.length == 0 ) 882 { 883 tuple.addAll( this.tuple ); 884 } 885 else 886 { 887 for( int i : pos ) 888 tuple.add( this.tuple.getObject( i ) ); 889 } 890 891 return tuple; 892 } 893 894 /** 895 * Method setTuple sets the values specified by the selector to the values given by the given tuple, the given 896 * values will always be copied into this TupleEntry. 897 * 898 * @param selector of type Fields 899 * @param tuple of type Tuple 900 */ 901 public void setTuple( Fields selector, Tuple tuple ) 902 { 903 if( selector == null || selector.isAll() ) 904 this.tuple.setAll( tuple ); 905 else 906 this.tuple.set( fields, selector, tuple ); 907 } 908 909 /** 910 * Method set sets the values from the given tupleEntry into this TupleEntry instance based on the given 911 * tupleEntry field names. 912 * <p/> 913 * If type information is given, each incoming value will be coerced from its canonical type to the given types. 914 * 915 * @param tupleEntry of type TupleEntry 916 */ 917 public void set( TupleEntry tupleEntry ) 918 { 919 this.tuple.set( fields, tupleEntry.getFields(), tupleEntry.getTuple(), tupleEntry.coercions ); 920 } 921 922 /** 923 * Method appendNew appends the given TupleEntry instance to this instance. 924 * 925 * @param entry of type TupleEntry 926 * @return TupleEntry 927 */ 928 public TupleEntry appendNew( TupleEntry entry ) 929 { 930 Fields appendedFields = fields.append( entry.fields.isUnknown() ? Fields.size( entry.tuple.size() ) : entry.fields ); 931 Tuple appendedTuple = tuple.append( entry.tuple ); 932 933 return new TupleEntry( appendedFields, appendedTuple ); 934 } 935 936 @Override 937 public boolean equals( Object object ) 938 { 939 if( this == object ) 940 return true; 941 942 if( !( object instanceof TupleEntry ) ) 943 return false; 944 945 TupleEntry that = (TupleEntry) object; 946 947 if( fields != null ? !fields.equals( that.fields ) : that.fields != null ) 948 return false; 949 950 // use comparators if in the this side fields instance 951 if( tuple != null ? fields.compare( tuple, that.tuple ) != 0 : that.tuple != null ) 952 return false; 953 954 return true; 955 } 956 957 @Override 958 public int hashCode() 959 { 960 int result = fields != null ? fields.hashCode() : 0; 961 result = 31 * result + ( tuple != null ? tuple.hashCode() : 0 ); 962 return result; 963 } 964 965 @Override 966 public String toString() 967 { 968 if( fields == null ) 969 return "empty"; 970 else if( tuple == null ) 971 return "fields: " + fields.print(); 972 else 973 return "fields: " + fields.print() + " tuple: " + tuple.print(); 974 } 975 976 /** 977 * Method asIterableOf returns an {@link Iterable} instance that will coerce all Tuple elements 978 * into the given {@code type} parameter. 979 * <p/> 980 * This method honors any {@link cascading.tuple.type.CoercibleType} instances on the internal 981 * Fields instance for the specified Tuple element. 982 * 983 * @param type of type Class 984 * @return an Iterable 985 */ 986 public <T> Iterable<T> asIterableOf( final Class<T> type ) 987 { 988 return new Iterable<T>() 989 { 990 @Override 991 public Iterator<T> iterator() 992 { 993 final Iterator<CoercibleType> coercibleIterator = coercions.length == 0 ? 994 OBJECT_ITERATOR : 995 Arrays.asList( coercions ).iterator(); 996 997 final Iterator valuesIterator = tuple.iterator(); 998 999 return new Iterator<T>() 1000 { 1001 @Override 1002 public boolean hasNext() 1003 { 1004 return valuesIterator.hasNext(); 1005 } 1006 1007 @Override 1008 public T next() 1009 { 1010 Object next = valuesIterator.next(); 1011 1012 return (T) coercibleIterator.next().coerce( next, type ); 1013 } 1014 1015 @Override 1016 public void remove() 1017 { 1018 valuesIterator.remove(); 1019 } 1020 }; 1021 } 1022 }; 1023 } 1024 }