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.operation.function;
022    
023    import java.beans.ConstructorProperties;
024    import java.io.Serializable;
025    import java.util.Arrays;
026    
027    import cascading.flow.FlowProcess;
028    import cascading.operation.BaseOperation;
029    import cascading.operation.Filter;
030    import cascading.operation.FilterCall;
031    import cascading.operation.Function;
032    import cascading.operation.FunctionCall;
033    import cascading.operation.OperationCall;
034    import cascading.tuple.Fields;
035    import cascading.tuple.Tuple;
036    
037    /**
038     * Class SetValue is a utility {@link Function} that allows for a Tuple value to be returned based on the outcome
039     * of a given {@link Filter} operation.
040     * <p/>
041     * There are only two possible values, either {@link Filter#isRemove(cascading.flow.FlowProcess, cascading.operation.FilterCall)}
042     * returns {@code true} or {@code false}.
043     * <p/>
044     * If {@code false} is returned, most commonly the {@link Filter} passed and the Tuple should be kept. SetValue will then return
045     * the first value in the given values array, by default {@code true}. If the Filter returns {@code true}, the second
046     * value in the values array will be returned, by default {@code false}.
047     * <p/>
048     */
049    public class SetValue extends BaseOperation implements Function
050      {
051      /** Field filter */
052      private final Filter filter;
053      /** Field values */
054      private Tuple[] values = new Tuple[]{new Tuple( true ), new Tuple( false )};
055    
056      /**
057       * Constructor SetValue creates a new SetValue instance.
058       *
059       * @param fieldDeclaration of type Fields
060       * @param filter           of type Filter
061       */
062      @ConstructorProperties({"fieldDeclaration", "filter"})
063      public SetValue( Fields fieldDeclaration, Filter filter )
064        {
065        super( fieldDeclaration );
066        this.filter = filter;
067    
068        verify();
069        }
070    
071      /**
072       * Constructor SetValue creates a new SetValue instance.
073       *
074       * @param fieldDeclaration of type Fields
075       * @param filter           of type Filter
076       * @param firstValue       of type Serializable
077       * @param secondValue      of type Serializable
078       */
079      @ConstructorProperties({"fieldDeclaration", "filter", "firstValue", "secondValue"})
080      public SetValue( Fields fieldDeclaration, Filter filter, Serializable firstValue, Serializable secondValue )
081        {
082        super( fieldDeclaration );
083        this.filter = filter;
084        this.values = new Tuple[]{new Tuple( firstValue ), new Tuple( secondValue )};
085    
086        verify();
087        }
088    
089      public Serializable getFirstValue()
090        {
091        return (Serializable) values[ 0 ].getObject( 0 );
092        }
093    
094      public Serializable getSecondValue()
095        {
096        return (Serializable) values[ 1 ].getObject( 0 );
097        }
098    
099      private void verify()
100        {
101        if( fieldDeclaration.size() != 1 )
102          throw new IllegalArgumentException( "fieldDeclaration may only declare one field, was " + fieldDeclaration.print() );
103    
104        if( filter == null )
105          throw new IllegalArgumentException( "filter may not be null" );
106    
107        if( values == null || values.length != 2 )
108          throw new IllegalArgumentException( "values argument must contain two values" );
109        }
110    
111      @Override
112      public void prepare( FlowProcess flowProcess, OperationCall operationCall )
113        {
114        filter.prepare( flowProcess, operationCall );
115        }
116    
117      @Override
118      public void operate( FlowProcess flowProcess, FunctionCall functionCall )
119        {
120        boolean isRemove = !filter.isRemove( flowProcess, (FilterCall) functionCall );
121    
122        int pos = isRemove ? 0 : 1;
123    
124        functionCall.getOutputCollector().add( values[ pos ] );
125        }
126    
127      @Override
128      public void cleanup( FlowProcess flowProcess, OperationCall operationCall )
129        {
130        filter.cleanup( flowProcess, operationCall );
131        }
132    
133      @Override
134      public boolean equals( Object object )
135        {
136        if( this == object )
137          return true;
138        if( !( object instanceof SetValue ) )
139          return false;
140        if( !super.equals( object ) )
141          return false;
142    
143        SetValue setValue = (SetValue) object;
144    
145        if( filter != null ? !filter.equals( setValue.filter ) : setValue.filter != null )
146          return false;
147        if( !Arrays.equals( values, setValue.values ) )
148          return false;
149    
150        return true;
151        }
152    
153      @Override
154      public int hashCode()
155        {
156        int result = super.hashCode();
157        result = 31 * result + ( filter != null ? filter.hashCode() : 0 );
158        result = 31 * result + ( values != null ? Arrays.hashCode( values ) : 0 );
159        return result;
160        }
161      }