001    /*
002     * Copyright (c) 2007-2015 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.pipe.assembly;
022    
023    import java.beans.ConstructorProperties;
024    
025    import cascading.operation.Identity;
026    import cascading.pipe.Each;
027    import cascading.pipe.Pipe;
028    import cascading.pipe.SubAssembly;
029    import cascading.tuple.Fields;
030    
031    /**
032     * Class Coerce is a {@link SubAssembly} that will coerce all incoming {@link cascading.tuple.Tuple} values to
033     * the given types.
034     * <p/>
035     * If the given type is a primitive ({@code long}), and the tuple value is null, {@code 0} is returned.
036     * If the type is an Object ({@code java.lang.Long}), and the tuple value is {@code null}, {@code null} is returned.
037     * <p/>
038     * Coerce encapsulates the {@link Identity} function.
039     * <p/>
040     * Note if the resolved coerceFields size does not equal the number of given types there will be a
041     * runtime error during execution.
042     *
043     * @see cascading.pipe.SubAssembly
044     * @see cascading.operation.Identity
045     */
046    public class Coerce extends SubAssembly
047      {
048      /**
049       * Constructor Coerce creates a new Coerce instance that will coerce all input Tuple values.
050       * <p/>
051       * Note if the resolved coerceFields size does not equal the number of given types there will be a
052       * runtime error during execution. Declaring the fields that must be coerced is a suggested practice.
053       *
054       * @param previous of type Pipe
055       * @param types    of type Class...
056       */
057      @ConstructorProperties( {"previous", "types"} )
058      public Coerce( Pipe previous, Class... types )
059        {
060        super( previous );
061    
062        if( types.length == 0 )
063          throw new IllegalArgumentException( "given types array may not be zero length" );
064    
065        setTails( new Each( previous, new Identity( types ) ) );
066        }
067    
068      /**
069       * Constructor Coerce creates a new Coerce instance that will only coerce the given coerceFields Tuple values.
070       * <p/>
071       * Note the resulting output Tuple will contain all the original incoming Fields.
072       * <p/>
073       * Also note if the resolved coerceFields size does not equal the number of given types there will be a
074       * runtime error during execution.
075       *
076       * @param previous     of type Pipe
077       * @param coerceFields of type Fields
078       * @param types        of type Class...
079       */
080      @ConstructorProperties( {"previous", "coerceFields", "types"} )
081      public Coerce( Pipe previous, Fields coerceFields, Class... types )
082        {
083        super( previous );
084    
085        if( coerceFields == null )
086          throw new IllegalArgumentException( "coerceFields may not be null" );
087    
088        if( types.length == 0 )
089          throw new IllegalArgumentException( "given types array may not be zero length" );
090    
091        setTails( new Each( previous, coerceFields, new Identity( types ), Fields.REPLACE ) );
092        }
093    
094      /**
095       * Constructor Coerce creates a new Coerce instance that will only coerce the given coerceFields Tuple values.
096       * <p/>
097       * The given {@code coerceFields} instance must contain field type information, otherwise an
098       * {@link IllegalArgumentException} will be thrown.
099       * <p/>
100       * Note the resulting output Tuple will contain all the original incoming Fields.
101       *
102       * @param previous     of type Pipe
103       * @param coerceFields of type Fields
104       */
105      @ConstructorProperties( {"previous", "coerceFields"} )
106      public Coerce( Pipe previous, Fields coerceFields )
107        {
108        super( previous );
109    
110        if( coerceFields == null )
111          throw new IllegalArgumentException( "coerceFields may not be null" );
112    
113        if( !coerceFields.hasTypes() )
114          throw new IllegalArgumentException( "coerceFields must have field types declared" );
115    
116        setTails( new Each( previous, coerceFields, new Identity( coerceFields ), Fields.REPLACE ) );
117    
118        if( coerceFields.getTypes().length == 0 )
119          throw new IllegalArgumentException( "number of types must not be zero" );
120        }
121      }