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