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.Arrays;
026import java.util.Iterator;
027
028import cascading.tuple.Fields;
029import cascading.tuple.Tuple;
030
031/**
032 * Class MixedJoin will return an {@link java.util.Iterator} that will iterate over a given
033 * {@link Joiner} and return tuples that represent a join as defined by the given boolean array.
034 * <p>
035 * So if joining three streams, {@code boolean []{true,false,false}} will result in a 'inner', 'outer', 'outer' join.
036 * <p>
037 * Joins perform based on the equality of the join keys. In the case of null values, Java treats two
038 * null values as equivalent. SQL does not treat null values as equal. To produce SQL like results in a given
039 * join, a new {@link java.util.Comparator} will need to be used on the joined values to prevent null from
040 * equaling null. As a convenience, see the {@link cascading.util.NullNotEquivalentComparator} class.
041 */
042public class MixedJoin extends BaseJoiner
043  {
044  /** Field INNER */
045  public static boolean INNER = true;
046  /** Field OUTER */
047  public static boolean OUTER = false;
048
049  final boolean[] asInner;
050
051  /**
052   * Constructor MixedJoin creates a new MixedJoin instance.
053   *
054   * @param asInner of type boolean[]
055   */
056  @ConstructorProperties({"asInner"})
057  public MixedJoin( boolean[] asInner )
058    {
059    this.asInner = Arrays.copyOf( asInner, asInner.length );
060    }
061
062  @ConstructorProperties({"fieldDeclaration", "asInner"})
063  public MixedJoin( Fields fieldDeclaration, boolean[] asInner )
064    {
065    super( fieldDeclaration );
066    this.asInner = asInner;
067    }
068
069  /** @see Joiner#numJoins() */
070  public int numJoins()
071    {
072    return asInner.length - 1;
073    }
074
075  public Iterator<Tuple> getIterator( JoinerClosure closure )
076    {
077    return new JoinIterator( closure );
078    }
079
080  public class JoinIterator extends OuterJoin.JoinIterator
081    {
082    public JoinIterator( JoinerClosure closure )
083      {
084      super( closure );
085      }
086
087    @Override
088    protected boolean isOuter( int i )
089      {
090      return !asInner[ i ] && super.isOuter( i );
091      }
092    }
093  }