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 coercions = getCoercions( getFields(), tuple ); 261 } 262 263 static CoercibleType[] getCoercions( Fields fields, Tuple tuple ) 264 { 265 Type[] types = fields.types; // safe to not get a copy 266 int size = fields.size(); 267 268 size = size == 0 && tuple != null ? tuple.size() : size; 269 270 if( size == 0 ) 271 return EMPTY_COERCIONS; 272 273 return Coercions.coercibleArray( size, types ); 274 } 275 276 /** 277 * Method isUnmodifiable returns true if this TupleEntry is unmodifiable. 278 * 279 * @return boolean 280 */ 281 public boolean isUnmodifiable() 282 { 283 return isUnmodifiable; 284 } 285 286 /** 287 * Method getFields returns the fields of this TupleEntry object. 288 * 289 * @return the fields (type Fields) of this TupleEntry object. 290 */ 291 public Fields getFields() 292 { 293 return fields; 294 } 295 296 /** 297 * Returns true if there are types associated with this instance. 298 * 299 * @return boolean 300 */ 301 public boolean hasTypes() 302 { 303 return fields.hasTypes(); 304 } 305 306 /** 307 * Method getTuple returns the tuple of this TupleEntry object. 308 * 309 * @return the tuple (type Tuple) of this TupleEntry object. 310 */ 311 public Tuple getTuple() 312 { 313 return tuple; 314 } 315 316 /** 317 * Method getTupleCopy returns a copy of the tuple of this TupleEntry object. 318 * 319 * @return a copy of the tuple (type Tuple) of this TupleEntry object. 320 */ 321 public Tuple getTupleCopy() 322 { 323 return new Tuple( tuple ); 324 } 325 326 /** 327 * Method getCoercedTuple is a helper method for copying the current tuple elements into a new Tuple, 328 * of the same size, as the requested coerced types. 329 * 330 * @param types of type Type[] 331 * @return returns the a new Tuple instance with coerced values 332 */ 333 public Tuple getCoercedTuple( Type[] types ) 334 { 335 return getCoercedTuple( types, Tuple.size( types.length ) ); 336 } 337 338 /** 339 * Method getCoercedTuple is a helper method for copying the current tuple elements into the new Tuple, 340 * of the same size, as the requested coerced types. 341 * 342 * @param types of type Type[] 343 * @param into of type Tuple 344 * @return returns the given into Tuple instance with coerced values 345 */ 346 public Tuple getCoercedTuple( Type[] types, Tuple into ) 347 { 348 if( coercions.length != types.length || types.length != into.size() ) 349 throw new IllegalArgumentException( "current entry and given tuple and types must be same length" ); 350 351 for( int i = 0; i < coercions.length; i++ ) 352 { 353 Object element = tuple.getObject( i ); 354 into.set( i, Coercions.coerce( coercions[ i ], element, types[ i ] ) ); 355 } 356 357 return into; 358 } 359 360 /** 361 * Method setTuple sets the tuple of this TupleEntry object, no copy will be performed. 362 * <p/> 363 * If the given tuple is "unmodifiable" ({@code Tuple.isUnmodifiable() == true}) and this TupleEntry is 364 * not "unmodifiable", an exception will be thrown. 365 * <p/> 366 * Unmodifiable tuples are generally owned by the system and cannot be be changed and must not be cached. 367 * 368 * @param tuple the tuple of this TupleEntry object. 369 */ 370 public void setTuple( Tuple tuple ) 371 { 372 if( !isUnmodifiable && tuple.isUnmodifiable() ) 373 throw new IllegalArgumentException( "current entry is modifiable but given tuple is not modifiable, make copy of given Tuple first" ); 374 375 if( tuple != null && isUnmodifiable ) 376 this.tuple = Tuples.asUnmodifiable( tuple ); 377 else 378 this.tuple = tuple; 379 380 setCoercions(); 381 } 382 383 /** 384 * Method setCanonicalTuple replaces each value of the current tuple with the given tuple elements after 385 * they are coerced. 386 * <p/> 387 * This method will modify the existing Tuple wrapped by this TupleEntry instance even 388 * if it is marked as unmodifiable. 389 * 390 * @param tuple to replace the current wrapped Tuple instance 391 */ 392 public void setCanonicalTuple( Tuple tuple ) 393 { 394 if( isUnmodifiable ) 395 tuple = Tuples.asUnmodifiable( tuple ); 396 397 if( fields.size() != tuple.size() ) 398 throw new IllegalArgumentException( "current entry and given tuple must be same length" ); 399 400 for( int i = 0; i < coercions.length; i++ ) 401 { 402 Object element = tuple.getObject( i ); 403 404 this.tuple.set( i, coercions[ i ].canonical( element ) ); // force read type to the expected type 405 } 406 } 407 408 /** 409 * Method setCanonicalValues replaces each value of the current tuple with th give Object[] 410 * after they are coerced. 411 * 412 * @param values to replace the current wrapped tuple instance values 413 */ 414 public void setCanonicalValues( Object[] values ) 415 { 416 if( fields.size() != values.length ) 417 throw new IllegalArgumentException( "current entry and given array must be same length" ); 418 419 for( int i = 0; i < coercions.length; i++ ) 420 { 421 Object element = values[ i ]; 422 423 this.tuple.set( i, coercions[ i ].canonical( element ) ); // force read type to the expected type 424 } 425 } 426 427 /** 428 * Method size returns the number of values in this instance. 429 * 430 * @return int 431 */ 432 public int size() 433 { 434 return tuple.size(); 435 } 436 437 /** 438 * Method get returns the value in the given position pos. 439 * <p/> 440 * This method is deprecated, use {@link #getObject(int)} instead. 441 * 442 * @param pos position of the element to return. 443 * @return Comparable 444 */ 445 @Deprecated 446 public Comparable get( int pos ) 447 { 448 return tuple.get( pos ); 449 } 450 451 /** 452 * Method getObject returns the value in the given position pos. 453 * <p/> 454 * No coercion is performed if there is an associated coercible type. 455 * 456 * @param pos position of the element to return. 457 * @return Object 458 */ 459 public Object getObject( int pos ) 460 { 461 return tuple.getObject( pos ); 462 } 463 464 /** 465 * Method getObject returns the value in the given field or position as the requested type. 466 * <p/> 467 * Coercion is performed to the given type. 468 * 469 * @param pos position of the element to return. 470 * @return Object 471 */ 472 public Object getObject( int pos, Type type ) 473 { 474 return Coercions.coerce( coercions[ pos ], tuple.getObject( pos ), type ); 475 } 476 477 /** 478 * Method get returns the value in the given field or position. 479 * <br/> 480 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 481 * be considered. 482 * <p/> 483 * This method is deprecated, use {@link #getObject(Comparable)} instead. 484 * 485 * @param fieldName field name or position to return 486 * @return Comparable 487 */ 488 @Deprecated 489 public Comparable get( Comparable fieldName ) 490 { 491 return tuple.get( fields.getPos( asFieldName( fieldName ) ) ); 492 } 493 494 /** 495 * Method getObject returns the value in the given field or position. 496 * <br/> 497 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 498 * be considered. 499 * <p/> 500 * No coercion is performed if there is an associated coercible type. 501 * 502 * @param fieldName field name or position to return 503 * @return Comparable 504 */ 505 public Object getObject( Comparable fieldName ) 506 { 507 int pos = fields.getPos( asFieldName( fieldName ) ); 508 return tuple.getObject( pos ); 509 } 510 511 /** 512 * Method getObject returns the value in the given field or position as the requested type. 513 * <br/> 514 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 515 * be considered. 516 * <p/> 517 * Coercion is performed to the given type. 518 * 519 * @param fieldName field name or position to return 520 * @return Comparable 521 */ 522 public Object getObject( Comparable fieldName, Type type ) 523 { 524 int pos = fields.getPos( asFieldName( fieldName ) ); 525 return Coercions.coerce( coercions[ pos ], tuple.getObject( pos ), type ); 526 } 527 528 /** 529 * Method set sets the value in the given field or position. 530 * <p/> 531 * This method is deprecated in favor of {@link #setRaw(Comparable, Object)} 532 * 533 * @param fieldName field name or position to set 534 * @param value of type Comparable 535 */ 536 @Deprecated 537 public void set( Comparable fieldName, Object value ) 538 { 539 tuple.set( fields.getPos( asFieldName( fieldName ) ), value ); 540 } 541 542 /** 543 * Method set sets the value in the given position. 544 * <p/> 545 * No coercion is performed if there is an associated coercible type. 546 * 547 * @param pos position to set 548 * @param value of type Comparable 549 */ 550 public void setRaw( int pos, Object value ) 551 { 552 tuple.set( pos, value ); 553 } 554 555 /** 556 * Method set sets the value in the given field or position. 557 * <p/> 558 * No coercion is performed if there is an associated coercible type. 559 * 560 * @param fieldName field name or position to set 561 * @param value of type Comparable 562 */ 563 public void setRaw( Comparable fieldName, Object value ) 564 { 565 tuple.set( fields.getPos( asFieldName( fieldName ) ), value ); 566 } 567 568 /** 569 * Method set sets the value in the given field or position. 570 * 571 * @param fieldName field name or position to set 572 * @param value of type Comparable 573 */ 574 public void setObject( Comparable fieldName, Object value ) 575 { 576 int pos = fields.getPos( asFieldName( fieldName ) ); 577 578 tuple.set( pos, coercions[ pos ].canonical( value ) ); 579 } 580 581 /** 582 * Method setBoolean sets the value in the given field or position. 583 * 584 * @param fieldName field name or position to set 585 * @param value of type boolean 586 */ 587 public void setBoolean( Comparable fieldName, boolean value ) 588 { 589 int pos = fields.getPos( asFieldName( fieldName ) ); 590 591 tuple.set( pos, coercions[ pos ].canonical( value ) ); 592 } 593 594 /** 595 * Method setShort sets the value in the given field or position. 596 * 597 * @param fieldName field name or position to set 598 * @param value of type short 599 */ 600 public void setShort( Comparable fieldName, short value ) 601 { 602 int pos = fields.getPos( asFieldName( fieldName ) ); 603 604 tuple.set( pos, coercions[ pos ].canonical( value ) ); 605 } 606 607 /** 608 * Method setInteger sets the value in the given field or position. 609 * 610 * @param fieldName field name or position to set 611 * @param value of type int 612 */ 613 public void setInteger( Comparable fieldName, int value ) 614 { 615 int pos = fields.getPos( asFieldName( fieldName ) ); 616 617 tuple.set( pos, coercions[ pos ].canonical( value ) ); 618 } 619 620 /** 621 * Method setLong sets the value in the given field or position. 622 * 623 * @param fieldName field name or position to set 624 * @param value of type long 625 */ 626 public void setLong( Comparable fieldName, long value ) 627 { 628 int pos = fields.getPos( asFieldName( fieldName ) ); 629 630 tuple.set( pos, coercions[ pos ].canonical( value ) ); 631 } 632 633 /** 634 * Method setFloat sets the value in the given field or position. 635 * 636 * @param fieldName field name or position to set 637 * @param value of type float 638 */ 639 public void setFloat( Comparable fieldName, float value ) 640 { 641 int pos = fields.getPos( asFieldName( fieldName ) ); 642 643 tuple.set( pos, coercions[ pos ].canonical( value ) ); 644 } 645 646 /** 647 * Method setDouble sets the value in the given field or position. 648 * 649 * @param fieldName field name or position to set 650 * @param value of type double 651 */ 652 public void setDouble( Comparable fieldName, double value ) 653 { 654 int pos = fields.getPos( asFieldName( fieldName ) ); 655 656 tuple.set( pos, coercions[ pos ].canonical( value ) ); 657 } 658 659 /** 660 * Method setString sets the value in the given field or position. 661 * 662 * @param fieldName field name or position to set 663 * @param value of type String 664 */ 665 public void setString( Comparable fieldName, String value ) 666 { 667 int pos = fields.getPos( asFieldName( fieldName ) ); 668 tuple.set( pos, coercions[ pos ].canonical( value ) ); 669 } 670 671 /** 672 * Method getString returns the element for the given field name or position as a String. 673 * <br/> 674 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 675 * be considered. 676 * 677 * @param fieldName field name or position to return 678 * @return String 679 */ 680 public String getString( Comparable fieldName ) 681 { 682 return (String) getObject( fieldName, String.class ); 683 } 684 685 /** 686 * Method getFloat returns the element for the given field name or position as a float. Zero if null. 687 * <br/> 688 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 689 * be considered. 690 * 691 * @param fieldName field name or position to return 692 * @return float 693 */ 694 public float getFloat( Comparable fieldName ) 695 { 696 return (Float) getObject( fieldName, float.class ); 697 } 698 699 /** 700 * Method getDouble returns the element for the given field name or position as a double. Zero if null. 701 * <br/> 702 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 703 * be considered. 704 * 705 * @param fieldName field name or position to return 706 * @return double 707 */ 708 public double getDouble( Comparable fieldName ) 709 { 710 return (Double) getObject( fieldName, double.class ); 711 } 712 713 /** 714 * Method getInteger returns the element for the given field name or position as an int. Zero if null. 715 * <br/> 716 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 717 * be considered. 718 * 719 * @param fieldName field name or position to return 720 * @return int 721 */ 722 public int getInteger( Comparable fieldName ) 723 { 724 return (Integer) getObject( fieldName, int.class ); 725 } 726 727 /** 728 * Method getLong returns the element for the given field name or position as a long. Zero if null. 729 * <br/> 730 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 731 * be considered. 732 * 733 * @param fieldName field name or position to return 734 * @return long 735 */ 736 public long getLong( Comparable fieldName ) 737 { 738 return (Long) getObject( fieldName, long.class ); 739 } 740 741 /** 742 * Method getShort returns the element for the given field name or position as a short. Zero if null. 743 * <br/> 744 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 745 * be considered. 746 * 747 * @param fieldName field name or position to return 748 * @return short 749 */ 750 public short getShort( Comparable fieldName ) 751 { 752 return (Short) getObject( fieldName, short.class ); 753 } 754 755 /** 756 * Method getBoolean returns the element for the given field name or position as a boolean. 757 * If the value is (case ignored) the string 'true', a {@code true} value will be returned. {@code false} if null. 758 * <br/> 759 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 760 * be considered. 761 * 762 * @param fieldName field name or position to return 763 * @return boolean 764 */ 765 public boolean getBoolean( Comparable fieldName ) 766 { 767 return (Boolean) getObject( fieldName, boolean.class ); 768 } 769 770 private Comparable asFieldName( Comparable fieldName ) 771 { 772 return Fields.asFieldName( fieldName ); 773 } 774 775 /** 776 * Method selectEntry selects the fields specified in the selector from this instance. If {@link Fields#ALL} or the 777 * same fields as declared are given, {@code this} will be returned. 778 * <p/> 779 * The returned TupleEntry will be either modifiable or unmodifiable, depending on the state of this TupleEntry instance. 780 * <p/> 781 * See {@link #selectEntryCopy(Fields)} to guarantee a copy suitable for modifying or caching/storing in a collection. 782 * <p/> 783 * Note this is a bug fix and change from 2.0 and 2.1. In previous versions the modifiable state was dependent 784 * on the given selector. 785 * 786 * @param selector Fields selector that selects the values to return 787 * @return TupleEntry 788 */ 789 public TupleEntry selectEntry( Fields selector ) 790 { 791 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 792 return this; 793 794 if( selector.isNone() ) 795 return isUnmodifiable ? TupleEntry.NULL : new TupleEntry(); 796 797 return new TupleEntry( Fields.asDeclaration( selector ), tuple.get( this.fields, selector ), isUnmodifiable ); 798 } 799 800 /** 801 * Method selectEntry selects the fields specified in selector from this instance. 802 * <p/> 803 * It is guaranteed to return a new modifiable TupleEntry instance at a cost of copying data. 804 * <p/> 805 * The returned instance is safe to cache. 806 * 807 * @param selector Fields selector that selects the values to return 808 * @return TupleEntry 809 */ 810 public TupleEntry selectEntryCopy( Fields selector ) 811 { 812 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 813 return new TupleEntry( this ); 814 815 if( selector.isNone() ) 816 return new TupleEntry(); 817 818 return new TupleEntry( Fields.asDeclaration( selector ), tuple.get( this.fields, selector ) ); 819 } 820 821 /** 822 * Method selectTuple selects the fields specified in the selector from this instance. If {@link Fields#ALL} or the 823 * same fields as declared are given, {@code this.getTuple()} will be returned. 824 * <p/> 825 * The returned Tuple will be either modifiable or unmodifiable, depending on the state of this TupleEntry instance. 826 * <p/> 827 * See {@link #selectTupleCopy(Fields)} to guarantee a copy suitable for modifying or caching/storing in a collection. 828 * <p/> 829 * Note this is a bug fix and change from 2.0 and 2.1. In previous versions the modifiable state was dependent 830 * on the given selector. 831 * 832 * @param selector Fields selector that selects the values to return 833 * @return Tuple 834 */ 835 public Tuple selectTuple( Fields selector ) 836 { 837 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 838 return this.tuple; 839 840 if( selector.isNone() ) 841 return Tuple.NULL; 842 843 Tuple result = tuple.get( fields, selector ); 844 845 if( isUnmodifiable ) 846 Tuples.asUnmodifiable( result ); 847 848 return result; 849 } 850 851 /** 852 * Method selectTupleCopy selects the fields specified in selector from this instance. 853 * <p/> 854 * It is guaranteed to return a new modifiable Tuple instance at a cost of copying data. 855 * <p/> 856 * The returned instance is safe to cache. 857 * 858 * @param selector Fields selector that selects the values to return 859 * @return Tuple 860 */ 861 public Tuple selectTupleCopy( Fields selector ) 862 { 863 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 864 return new Tuple( this.tuple ); 865 866 if( selector.isNone() ) 867 return new Tuple(); 868 869 return tuple.get( fields, selector ); 870 } 871 872 /** 873 * Method selectInto selects the fields specified in the selector from this instance and copies 874 * them into the given tuple argument. 875 * 876 * @param selector of type Fields 877 * @param tuple of type Tuple 878 * @return returns the given tuple argument with new values added 879 */ 880 public Tuple selectInto( Fields selector, Tuple tuple ) 881 { 882 if( selector.isNone() ) 883 return tuple; 884 885 int[] pos = this.tuple.getPos( fields, selector ); 886 887 if( pos == null || pos.length == 0 ) 888 { 889 tuple.addAll( this.tuple ); 890 } 891 else 892 { 893 for( int i : pos ) 894 tuple.add( this.tuple.getObject( i ) ); 895 } 896 897 return tuple; 898 } 899 900 /** 901 * Method setTuple sets the values specified by the selector to the values given by the given tuple, the given 902 * values will always be copied into this TupleEntry. 903 * 904 * @param selector of type Fields 905 * @param tuple of type Tuple 906 */ 907 public void setTuple( Fields selector, Tuple tuple ) 908 { 909 if( selector == null || selector.isAll() ) 910 this.tuple.setAll( tuple ); 911 else 912 this.tuple.set( fields, selector, tuple ); 913 } 914 915 /** 916 * Method set sets the values from the given tupleEntry into this TupleEntry instance based on the given 917 * tupleEntry field names. 918 * <p/> 919 * If type information is given, each incoming value will be coerced from its canonical type to the current type. 920 * 921 * @param tupleEntry of type TupleEntry 922 */ 923 public void set( TupleEntry tupleEntry ) 924 { 925 this.tuple.set( fields, tupleEntry.getFields(), tupleEntry.getTuple(), tupleEntry.coercions ); 926 } 927 928 /** 929 * Method appendNew appends the given TupleEntry instance to this instance. 930 * 931 * @param entry of type TupleEntry 932 * @return TupleEntry 933 */ 934 public TupleEntry appendNew( TupleEntry entry ) 935 { 936 Fields appendedFields = fields.append( entry.fields.isUnknown() ? Fields.size( entry.tuple.size() ) : entry.fields ); 937 Tuple appendedTuple = tuple.append( entry.tuple ); 938 939 return new TupleEntry( appendedFields, appendedTuple ); 940 } 941 942 @Override 943 public boolean equals( Object object ) 944 { 945 if( this == object ) 946 return true; 947 948 if( !( object instanceof TupleEntry ) ) 949 return false; 950 951 TupleEntry that = (TupleEntry) object; 952 953 if( fields != null ? !fields.equals( that.fields ) : that.fields != null ) 954 return false; 955 956 // use comparators if in the this side fields instance 957 if( tuple != null ? fields.compare( tuple, that.tuple ) != 0 : that.tuple != null ) 958 return false; 959 960 return true; 961 } 962 963 @Override 964 public int hashCode() 965 { 966 int result = fields != null ? fields.hashCode() : 0; 967 result = 31 * result + ( tuple != null ? tuple.hashCode() : 0 ); 968 return result; 969 } 970 971 @Override 972 public String toString() 973 { 974 if( fields == null ) 975 return "empty"; 976 else if( tuple == null ) 977 return "fields: " + fields.print(); 978 else 979 return "fields: " + fields.print() + " tuple: " + tuple.print(); 980 } 981 982 /** 983 * Method asIterableOf returns an {@link Iterable} instance that will coerce all Tuple elements 984 * into the given {@code type} parameter. 985 * <p/> 986 * This method honors any {@link cascading.tuple.type.CoercibleType} instances on the internal 987 * Fields instance for the specified Tuple element. 988 * 989 * @param type of type Class 990 * @return an Iterable 991 */ 992 public <T> Iterable<T> asIterableOf( final Class<T> type ) 993 { 994 return new Iterable<T>() 995 { 996 @Override 997 public Iterator<T> iterator() 998 { 999 final Iterator<CoercibleType> coercibleIterator = coercions.length == 0 ? 1000 OBJECT_ITERATOR : 1001 Arrays.asList( coercions ).iterator(); 1002 1003 final Iterator valuesIterator = tuple.iterator(); 1004 1005 return new Iterator<T>() 1006 { 1007 @Override 1008 public boolean hasNext() 1009 { 1010 return valuesIterator.hasNext(); 1011 } 1012 1013 @Override 1014 public T next() 1015 { 1016 Object next = valuesIterator.next(); 1017 1018 return (T) coercibleIterator.next().coerce( next, type ); 1019 } 1020 1021 @Override 1022 public void remove() 1023 { 1024 valuesIterator.remove(); 1025 } 1026 }; 1027 } 1028 }; 1029 } 1030 }