001/* 002 * Copyright (c) 2016-2017 Chris K Wensel <chris@wensel.net>. All Rights Reserved. 003 * Copyright (c) 2007-2017 Xplenty, Inc. All Rights Reserved. 004 * 005 * Project and contact information: http://www.cascading.org/ 006 * 007 * This file is part of the Cascading project. 008 * 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 */ 021 022package cascading.pipe.joiner; 023 024import java.beans.ConstructorProperties; 025import java.util.Collections; 026import java.util.Iterator; 027import java.util.List; 028 029import cascading.tuple.Fields; 030import cascading.tuple.Tuple; 031 032/** 033 * Class OuterJoin will return an {@link Iterator} that will iterate over a given {@link Joiner} and return tuples that represent 034 * and outer join of the CoGrouper internal grouped tuple collections. 035 * <p> 036 * Joins perform based on the equality of the join keys. In the case of null values, Java treats two 037 * null values as equivalent. SQL does not treat null values as equal. To produce SQL like results in a given 038 * join, a new {@link java.util.Comparator} will need to be used on the joined values to prevent null from 039 * equaling null. As a convenience, see the {@link cascading.util.NullNotEquivalentComparator} class. 040 */ 041public class OuterJoin extends BaseJoiner 042 { 043 public OuterJoin() 044 { 045 } 046 047 @ConstructorProperties({"fieldDeclaration"}) 048 public OuterJoin( Fields fieldDeclaration ) 049 { 050 super( fieldDeclaration ); 051 } 052 053 public Iterator<Tuple> getIterator( JoinerClosure closure ) 054 { 055 return new JoinIterator( closure ); 056 } 057 058 public int numJoins() 059 { 060 return -1; 061 } 062 063 public static class JoinIterator extends InnerJoin.JoinIterator 064 { 065 List[] singletons; 066 067 public JoinIterator( JoinerClosure closure ) 068 { 069 super( closure ); 070 } 071 072 @Override 073 protected void init() 074 { 075 singletons = new List[ closure.size() ]; 076 077 for( int i = 0; i < singletons.length; i++ ) 078 { 079 if( isOuter( i ) ) 080 singletons[ i ] = Collections.singletonList( Tuple.size( closure.getValueFields()[ i ].size() ) ); 081 } 082 083 super.init(); 084 } 085 086 protected boolean isOuter( int i ) 087 { 088 return closure.isEmpty( i ); 089 } 090 091 @Override 092 protected Iterator getIterator( int i ) 093 { 094 if( singletons[ i ] == null ) // let init() decide 095 return super.getIterator( i ); 096 097 return singletons[ i ].iterator(); 098 } 099 } 100 }