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      }