001/*
002 * Copyright (c) 2007-2022 The Cascading Authors. All Rights Reserved.
003 *
004 * Project and contact information: https://cascading.wensel.net/
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
021package cascading.tuple.hadoop.io;
022
023import java.io.DataInputStream;
024import java.io.IOException;
025import java.io.InputStream;
026import java.util.IdentityHashMap;
027import java.util.Map;
028
029import cascading.tuple.Tuple;
030import cascading.tuple.io.IndexTuple;
031import cascading.tuple.io.TupleInputStream;
032import cascading.tuple.io.TuplePair;
033import org.apache.hadoop.io.WritableUtils;
034
035/**
036 *
037 */
038public class HadoopTupleInputStream extends TupleInputStream
039  {
040  private static final Map<Class, TupleElementReader> staticTupleUnTypedElementReaders = new IdentityHashMap<>();
041  private static final Map<Class, TupleElementReader> staticTupleTypedElementReaders = new IdentityHashMap<>();
042
043  static
044    {
045    // typed
046
047    staticTupleTypedElementReaders.put( Void.class, (TupleElementReader<HadoopTupleInputStream>) stream -> null );
048
049    staticTupleTypedElementReaders.put( String.class, (TupleElementReader<HadoopTupleInputStream>) HadoopTupleInputStream::readString );
050
051    staticTupleTypedElementReaders.put( Float.class, (TupleElementReader<HadoopTupleInputStream>) HadoopTupleInputStream::readNullFloat );
052
053    staticTupleTypedElementReaders.put( Double.class, (TupleElementReader<HadoopTupleInputStream>) HadoopTupleInputStream::readNullDouble );
054
055    staticTupleTypedElementReaders.put( Integer.class, (TupleElementReader<HadoopTupleInputStream>) HadoopTupleInputStream::readNullVInt );
056
057    staticTupleTypedElementReaders.put( Long.class, (TupleElementReader<HadoopTupleInputStream>) HadoopTupleInputStream::readNullVLong );
058
059    staticTupleTypedElementReaders.put( Boolean.class, (TupleElementReader<HadoopTupleInputStream>) HadoopTupleInputStream::readNullBoolean );
060
061    staticTupleTypedElementReaders.put( Short.class, (TupleElementReader<HadoopTupleInputStream>) HadoopTupleInputStream::readNullShort );
062
063    staticTupleTypedElementReaders.put( Float.TYPE, (TupleElementReader<HadoopTupleInputStream>) DataInputStream::readFloat );
064
065    staticTupleTypedElementReaders.put( Double.TYPE, (TupleElementReader<HadoopTupleInputStream>) DataInputStream::readDouble );
066
067    staticTupleTypedElementReaders.put( Integer.TYPE, (TupleElementReader<HadoopTupleInputStream>) HadoopTupleInputStream::readVInt );
068
069    staticTupleTypedElementReaders.put( Long.TYPE, (TupleElementReader<HadoopTupleInputStream>) HadoopTupleInputStream::readVLong );
070
071    staticTupleTypedElementReaders.put( Boolean.TYPE, (TupleElementReader<HadoopTupleInputStream>) DataInputStream::readBoolean );
072
073    staticTupleTypedElementReaders.put( Short.TYPE, (TupleElementReader<HadoopTupleInputStream>) DataInputStream::readShort );
074
075    staticTupleTypedElementReaders.put( Tuple.class, (TupleElementReader<HadoopTupleInputStream>) TupleInputStream::readTuple );
076
077    staticTupleTypedElementReaders.put( TuplePair.class, (TupleElementReader<HadoopTupleInputStream>) TupleInputStream::readTuplePair );
078
079    staticTupleTypedElementReaders.put( IndexTuple.class, (TupleElementReader<HadoopTupleInputStream>) TupleInputStream::readIndexTuple );
080    }
081
082  public static TupleElementReader[] getReadersFor( final ElementReader elementReader, final Class[] classes )
083    {
084    if( classes == null || classes.length == 0 )
085      return null;
086
087    TupleElementReader[] readers = new TupleElementReader[ classes.length ];
088
089    for( int i = 0; i < classes.length; i++ )
090      {
091      TupleElementReader reader = staticTupleTypedElementReaders.get( classes[ i ] );
092
093      if( reader != null )
094        {
095        readers[ i ] = reader;
096        }
097      else
098        {
099        final int index = i;
100        readers[ i ] = stream -> elementReader.read( classes[ index ], stream );
101        }
102      }
103
104    return readers;
105    }
106
107  public HadoopTupleInputStream( InputStream inputStream, ElementReader elementReader )
108    {
109    super( inputStream, elementReader );
110    }
111
112  public int getNumElements() throws IOException
113    {
114    return readVInt();
115    }
116
117  public int readToken() throws IOException
118    {
119    return readVInt();
120    }
121
122  public Object getNextElement() throws IOException
123    {
124    return readType( readToken() );
125    }
126
127  public IndexTuple readIndexTuple( IndexTuple tuple ) throws IOException
128    {
129    tuple.setIndex( readVInt() );
130    tuple.setTuple( readTuple() );
131
132    return tuple;
133    }
134
135  public Long readNullVLong() throws IOException
136    {
137    byte b = this.readByte();
138
139    if( b == 0 )
140      return null;
141
142    return WritableUtils.readVLong( this );
143    }
144
145  public long readVLong() throws IOException
146    {
147    return WritableUtils.readVLong( this );
148    }
149
150  public Integer readNullVInt() throws IOException
151    {
152    byte b = this.readByte();
153
154    if( b == 0 )
155      return null;
156
157    return WritableUtils.readVInt( this );
158    }
159
160  public int readVInt() throws IOException
161    {
162    return WritableUtils.readVInt( this );
163    }
164
165  public String readString() throws IOException
166    {
167    return WritableUtils.readString( this );
168    }
169
170  private Short readNullShort() throws IOException
171    {
172    byte b = this.readByte();
173
174    if( b == 0 )
175      return null;
176
177    return readShort();
178    }
179
180  private Object readNullBoolean() throws IOException
181    {
182    byte b = this.readByte();
183
184    if( b == 0 )
185      return null;
186
187    return readBoolean();
188    }
189
190  private Object readNullDouble() throws IOException
191    {
192    byte b = this.readByte();
193
194    if( b == 0 )
195      return null;
196
197    return readDouble();
198    }
199
200  private Object readNullFloat() throws IOException
201    {
202    byte b = this.readByte();
203
204    if( b == 0 )
205      return null;
206
207    return readFloat();
208    }
209
210  protected final Object readType( int type ) throws IOException
211    {
212    switch( type )
213      {
214      case 0:
215        return null;
216      case 1:
217        return readString();
218      case 2:
219        return readFloat();
220      case 3:
221        return readDouble();
222      case 4:
223        return readVInt();
224      case 5:
225        return readVLong();
226      case 6:
227        return readBoolean();
228      case 7:
229        return readShort();
230      case 8:
231        return readTuple();
232      case 9:
233        return readTuplePair();
234      case 10:
235        return readIndexTuple();
236      default:
237        return elementReader.read( type, this );
238      }
239    }
240
241  public final Object readType( Class type ) throws IOException
242    {
243    if( type == Void.class )
244      return null;
245
246    if( type == String.class )
247      return readString();
248
249    if( type == Float.class )
250      return readNullFloat();
251    if( type == Double.class )
252      return readNullDouble();
253    if( type == Integer.class )
254      return readNullVInt();
255    if( type == Long.class )
256      return readNullVLong();
257    if( type == Boolean.class )
258      return readNullBoolean();
259    if( type == Short.class )
260      return readNullShort();
261
262    if( type == Float.TYPE )
263      return readFloat();
264    if( type == Double.TYPE )
265      return readDouble();
266    if( type == Integer.TYPE )
267      return readVInt();
268    if( type == Long.TYPE )
269      return readVLong();
270    if( type == Boolean.TYPE )
271      return readBoolean();
272    if( type == Short.TYPE )
273      return readShort();
274
275    if( type == Tuple.class )
276      return readTuple();
277    if( type == TuplePair.class )
278      return readTuplePair();
279    if( type == IndexTuple.class )
280      return readIndexTuple();
281    else
282      return elementReader.read( type, this );
283    }
284  }