fr.groupbees.asgarde.transforms.MapElementFn Maven / Gradle / Ivy
Show all versions of asgarde Show documentation
package fr.groupbees.asgarde.transforms;
import fr.groupbees.asgarde.Failure;
import org.apache.beam.sdk.transforms.SerializableFunction;
import org.apache.beam.sdk.values.TypeDescriptor;
import org.apache.beam.sdk.values.TypeDescriptors;
import static java.util.Objects.requireNonNull;
/**
* This class allows to handle a generic and custom {@link org.apache.beam.sdk.transforms.DoFn} for map operation
* with error handling.
*
*
* This class is based on a output type descriptor and take a {@link SerializableFunction} to execute the mapping treatment
* lazily. This output type allows to give type information and handle default coder for output.
* This function is mandatory and executed in the ProcessElement stage of Beam lifecycle.
*
*
*
* This class can take a start action {@link SerializableAction}, used in the setup of Beam lifecycle.
* This function is not required and if it passed, it is executed lazily in the setup process.
*
*
*
* If there are errors in the process, an failure Tag based on {@link Failure} object is used to handle
* the failure output (and side outputs)
*
*
* Example usage:
*
*
{@code
* // With serializable function but without start action.
* MapElementFn.into(TypeDescriptors.integers())
* .via((String word) -> 1 / word.length) // Could throw ArithmeticException
*
* // With serializable function but without start action.
* MapElementFn.into(TypeDescriptors.integers())
* .via((String word) -> 1 / word.length)
* .withSetupAction(() -> System.out.println("Starting of mapping...")
* }
*
*
*/
public class MapElementFn extends BaseElementFn {
private final SerializableAction setupAction;
private final SerializableFunction inputElementMapper;
private MapElementFn(TypeDescriptor inputType,
TypeDescriptor outputType,
SerializableAction setupAction,
SerializableFunction inputElementMapper) {
super(inputType, outputType);
this.setupAction = setupAction;
this.inputElementMapper = inputElementMapper;
}
/**
* Factory method of class, that take the output {@link TypeDescriptor}.
*/
public static MapElementFn, OutputT> into(final TypeDescriptor outputType) {
final SerializableAction defaultSetupAction = () -> {
};
return new MapElementFn<>(null, outputType, defaultSetupAction, null);
}
/**
* Method that takes the {@link SerializableFunction} that will be evaluated in the process element phase.
*
* This function is mandatory in process element phase.
*
* @param inputElementMapper serializable function from input and to output
*/
public MapElementFn via(final SerializableFunction inputElementMapper) {
requireNonNull(inputElementMapper);
final TypeDescriptor inputDescriptor = TypeDescriptors.inputOf(inputElementMapper);
return new MapElementFn<>(inputDescriptor, outputType, setupAction, inputElementMapper);
}
/**
* Method that takes the {@link SerializableAction} that will be evaluated in the setup element phase.
*
* This function is not mandatory in the setup phase.
*
* @param setupAction serializable action
*/
public MapElementFn withSetupAction(final SerializableAction setupAction) {
requireNonNull(inputElementMapper);
return new MapElementFn<>(inputType, outputType, setupAction, inputElementMapper);
}
@Setup
public void start() {
setupAction.execute();
}
@ProcessElement
public void processElement(ProcessContext ctx) {
requireNonNull(inputElementMapper);
try {
ctx.output(inputElementMapper.apply(ctx.element()));
} catch (Throwable throwable) {
final Failure failure = Failure.from(ctx.element(), throwable);
ctx.output(failuresTag, failure);
}
}
}