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.pipe.joiner; 022 023 import java.beans.ConstructorProperties; 024 import java.util.Collections; 025 import java.util.Iterator; 026 import java.util.List; 027 028 import cascading.tuple.Fields; 029 import cascading.tuple.Tuple; 030 031 /** 032 * Class OuterJoin will return an {@link Iterator} that will iterate over a given {@link Joiner} and return tuples that represent 033 * and outer join of the CoGrouper internal grouped tuple collections. 034 * <p/> 035 * Joins perform based on the equality of the join keys. In the case of null values, Java treats two 036 * null values as equivalent. SQL does not treat null values as equal. To produce SQL like results in a given 037 * join, a new {@link java.util.Comparator} will need to be used on the joined values to prevent null from 038 * equaling null. As a convenience, see the {@link cascading.util.NullNotEquivalentComparator} class. 039 */ 040 public class OuterJoin extends BaseJoiner 041 { 042 public OuterJoin() 043 { 044 } 045 046 @ConstructorProperties({"fieldDeclaration"}) 047 public OuterJoin( Fields fieldDeclaration ) 048 { 049 super( fieldDeclaration ); 050 } 051 052 public Iterator<Tuple> getIterator( JoinerClosure closure ) 053 { 054 return new JoinIterator( closure ); 055 } 056 057 public int numJoins() 058 { 059 return -1; 060 } 061 062 public static class JoinIterator extends InnerJoin.JoinIterator 063 { 064 List[] singletons; 065 066 public JoinIterator( JoinerClosure closure ) 067 { 068 super( closure ); 069 } 070 071 @Override 072 protected void init() 073 { 074 singletons = new List[ closure.size() ]; 075 076 for( int i = 0; i < singletons.length; i++ ) 077 { 078 if( isOuter( i ) ) 079 singletons[ i ] = Collections.singletonList( Tuple.size( closure.getValueFields()[ i ].size() ) ); 080 } 081 082 super.init(); 083 } 084 085 protected boolean isOuter( int i ) 086 { 087 return closure.isEmpty( i ); 088 } 089 090 @Override 091 protected Iterator getIterator( int i ) 092 { 093 if( singletons[ i ] == null ) // let init() decide 094 return super.getIterator( i ); 095 096 return singletons[ i ].iterator(); 097 } 098 } 099 }