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.IOException;
024import java.io.OutputStream;
025import java.util.IdentityHashMap;
026import java.util.Map;
027
028import cascading.tuple.Tuple;
029import cascading.tuple.io.IndexTuple;
030import cascading.tuple.io.TupleOutputStream;
031import cascading.tuple.io.TuplePair;
032import org.apache.hadoop.io.WritableUtils;
033
034/**
035 *
036 */
037public class HadoopTupleOutputStream extends TupleOutputStream
038  {
039  /** Field WRITABLE_TOKEN */
040  public static final int WRITABLE_TOKEN = 32;
041
042  private static final Map<Class, TupleElementWriter> staticTupleUnTypedElementWriters = new IdentityHashMap<>();
043  private static final Map<Class, TupleElementWriter> staticTupleTypedElementWriters = new IdentityHashMap<>();
044
045  static
046    {
047    // untyped
048
049    staticTupleUnTypedElementWriters.put( String.class, ( stream, element ) ->
050    {
051    WritableUtils.writeVInt( stream, 1 );
052    WritableUtils.writeString( stream, (String) element );
053    } );
054
055    staticTupleUnTypedElementWriters.put( Float.class, ( stream, element ) ->
056    {
057    WritableUtils.writeVInt( stream, 2 );
058    stream.writeFloat( (Float) element );
059    } );
060
061    staticTupleUnTypedElementWriters.put( Double.class, ( stream, element ) ->
062    {
063    WritableUtils.writeVInt( stream, 3 );
064    stream.writeDouble( (Double) element );
065    } );
066
067    staticTupleUnTypedElementWriters.put( Integer.class, ( stream, element ) ->
068    {
069    WritableUtils.writeVInt( stream, 4 );
070    WritableUtils.writeVInt( stream, (Integer) element );
071    } );
072
073    staticTupleUnTypedElementWriters.put( Long.class, ( stream, element ) ->
074    {
075    WritableUtils.writeVInt( stream, 5 );
076    WritableUtils.writeVLong( stream, (Long) element );
077    } );
078
079    staticTupleUnTypedElementWriters.put( Boolean.class, ( stream, element ) ->
080    {
081    WritableUtils.writeVInt( stream, 6 );
082    stream.writeBoolean( (Boolean) element );
083    } );
084
085    staticTupleUnTypedElementWriters.put( Short.class, ( stream, element ) ->
086    {
087    WritableUtils.writeVInt( stream, 7 );
088    stream.writeShort( (Short) element );
089    } );
090
091    staticTupleUnTypedElementWriters.put( Tuple.class, ( stream, element ) ->
092    {
093    WritableUtils.writeVInt( stream, 8 );
094    stream.writeTuple( (Tuple) element );
095    } );
096
097    staticTupleUnTypedElementWriters.put( TuplePair.class, ( stream, element ) ->
098    {
099    WritableUtils.writeVInt( stream, 9 );
100    stream.writeTuplePair( (TuplePair) element );
101    } );
102
103    staticTupleUnTypedElementWriters.put( IndexTuple.class, ( stream, element ) ->
104    {
105    WritableUtils.writeVInt( stream, 10 );
106    stream.writeIndexTuple( (IndexTuple) element );
107    } );
108
109    // typed
110
111    staticTupleTypedElementWriters.put( Void.class, ( stream, element ) ->
112    {
113    // do nothing
114    } );
115
116    staticTupleTypedElementWriters.put( String.class, ( stream, element ) -> WritableUtils.writeString( stream, (String) element ) );
117
118    staticTupleTypedElementWriters.put( Float.class, ( stream, element ) ->
119    {
120    if( element == null )
121      {
122      stream.writeByte( 0 );
123      return;
124      }
125
126    stream.writeByte( 1 );
127    stream.writeFloat( (Float) element );
128    } );
129
130    staticTupleTypedElementWriters.put( Double.class, ( stream, element ) ->
131    {
132    if( element == null )
133      {
134      stream.writeByte( 0 );
135      return;
136      }
137
138    stream.writeByte( 1 );
139    stream.writeDouble( (Double) element );
140    } );
141
142    staticTupleTypedElementWriters.put( Integer.class, ( stream, element ) ->
143    {
144    if( element == null )
145      {
146      stream.writeByte( 0 );
147      return;
148      }
149
150    stream.writeByte( 1 );
151    WritableUtils.writeVInt( stream, (Integer) element );
152    } );
153
154    staticTupleTypedElementWriters.put( Long.class, ( stream, element ) ->
155    {
156    if( element == null )
157      {
158      stream.writeByte( 0 );
159      return;
160      }
161
162    stream.writeByte( 1 );
163    WritableUtils.writeVLong( stream, (Long) element );
164    } );
165
166    staticTupleTypedElementWriters.put( Boolean.class, ( stream, element ) ->
167    {
168    if( element == null )
169      {
170      stream.writeByte( 0 );
171      return;
172      }
173
174    stream.writeByte( 1 );
175    stream.writeBoolean( (Boolean) element );
176    } );
177
178    staticTupleTypedElementWriters.put( Short.class, ( stream, element ) ->
179    {
180    if( element == null )
181      {
182      stream.writeByte( 0 );
183      return;
184      }
185
186    stream.writeByte( 1 );
187    stream.writeShort( (Short) element );
188    } );
189
190    staticTupleTypedElementWriters.put( Float.TYPE, ( stream, element ) ->
191    {
192    if( element == null )
193      stream.writeFloat( 0 );
194    else
195      stream.writeFloat( (Float) element );
196    } );
197
198    staticTupleTypedElementWriters.put( Double.TYPE, ( stream, element ) ->
199    {
200    if( element == null )
201      stream.writeDouble( 0 );
202    else
203      stream.writeDouble( (Double) element );
204    } );
205
206    staticTupleTypedElementWriters.put( Integer.TYPE, ( stream, element ) ->
207    {
208    if( element == null )
209      WritableUtils.writeVInt( stream, 0 );
210    else
211      WritableUtils.writeVInt( stream, (Integer) element );
212    } );
213
214    staticTupleTypedElementWriters.put( Long.TYPE, ( stream, element ) ->
215    {
216    if( element == null )
217      WritableUtils.writeVLong( stream, 0 );
218    else
219      WritableUtils.writeVLong( stream, (Long) element );
220    } );
221
222    staticTupleTypedElementWriters.put( Boolean.TYPE, ( stream, element ) ->
223    {
224    if( element == null )
225      stream.writeBoolean( false );
226    else
227      stream.writeBoolean( (Boolean) element );
228    } );
229
230    staticTupleTypedElementWriters.put( Short.TYPE, ( stream, element ) ->
231    {
232    if( element == null )
233      stream.writeShort( 0 );
234    else
235      stream.writeShort( (Short) element );
236    } );
237
238    staticTupleTypedElementWriters.put( Tuple.class, ( stream, element ) -> stream.writeTuple( (Tuple) element ) );
239
240    staticTupleTypedElementWriters.put( TuplePair.class, ( stream, element ) -> stream.writeTuplePair( (TuplePair) element ) );
241
242    staticTupleTypedElementWriters.put( IndexTuple.class, ( stream, element ) -> stream.writeIndexTuple( (IndexTuple) element ) );
243    }
244
245  public static TupleElementWriter[] getWritersFor( final ElementWriter elementWriter, final Class[] keyClasses )
246    {
247    if( keyClasses == null || keyClasses.length == 0 )
248      return null;
249
250    TupleElementWriter[] writers = new TupleElementWriter[ keyClasses.length ];
251
252    for( int i = 0; i < keyClasses.length; i++ )
253      {
254      TupleElementWriter writer = staticTupleTypedElementWriters.get( keyClasses[ i ] );
255
256      if( writer != null )
257        {
258        writers[ i ] = writer;
259        }
260      else
261        {
262        final int index = i;
263        writers[ i ] = ( stream, element ) -> elementWriter.write( stream, keyClasses[ index ], element );
264        }
265      }
266
267    return writers;
268    }
269
270  public HadoopTupleOutputStream( OutputStream outputStream, ElementWriter elementWriter )
271    {
272    super( staticTupleUnTypedElementWriters, staticTupleTypedElementWriters, outputStream, elementWriter );
273    }
274
275  @Override
276  protected void writeIntInternal( int value ) throws IOException
277    {
278    WritableUtils.writeVInt( this, value );
279    }
280
281  public void writeIndexTuple( IndexTuple indexTuple ) throws IOException
282    {
283    writeIntInternal( indexTuple.getIndex() );
284    writeTuple( indexTuple.getTuple() );
285    }
286  }