/* * This file is part of the GeoLatte project. * * GeoLatte is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GeoLatte is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with GeoLatte. If not, see <http://www.gnu.org/licenses/>. * * Copyright (C) 2010 - 2010 and Ownership of code is shared by: * Qmino bvba - Romeinsestraat 18 - 3001 Heverlee (http://www.qmino.com) * Geovise bvba - Generaal Eisenhowerlei 9 - 2140 Antwerpen (http://www.geovise.com) */ package org.geolatte.common.transformer; import java.util.ArrayList; /** * Allows the client to concatenate multiple Transformations and retrieve a single Transformation object that executes these in a chain. * This class offers a type-safe fluent interface to concatenate transformations. * Usage: * <pre> * {@code * CompositeTransformationFactory<Integer, String> factory = new CompositeTransformationFactory<Integer, String>(); * Transformation tf = factory.first(subtf) * .add(subtf) * .add(subtf) * .last(subtf); * } * </pre> * An object of this class can be reused to create different chains of the same type. * * @param <Source> The input type of the transformation. * @param <Target> The output type of the transformation. * * <p> * <i>Creation-Date</i>: 18-Mar-2010<br> * <i>Creation-Time</i>: 18:35:34<br> * </p> * * @author Bert Vanhooff * @author <a href="http://www.qmino.com">Qmino bvba</a> * @since SDK1.5 */ public class TransformationChainFactory<Source, Target> { private TransformationChain<Source, Target> transformationChain; /** * Adds the first sub-transformation to the chain. Subsequent transformations can be added by invoking methods on the TransformationConcatenator returned by this method. * * @param firstTransformation The first transformation in the chain. * @param <Intermediate> The type of the output produced by the (intermediate) transformation added. * * @return A TransformationConcatenator that allows to add additional transformations to the chain or close the chain. */ public <Intermediate> TransformationConcatenator<Intermediate, Target> first(Transformation<Source, Intermediate> firstTransformation) { transformationChain = new TransformationChain<Source, Target>(); transformationChain.chain.add(firstTransformation); return new TransformationConcatenator<Intermediate, Target>(); } /** * Internal helper class to facilitate the fluent interface for adding sub-transformations to CompositeTransformationFactory. * * @param <IntermediateSource> The the source/target of the current stage in the transformation chain (for the first add(), this is the Source type of the CompositeTransformationFactory). * @param <Target> The final target of the CompositeTransformationFactory */ class TransformationConcatenator<IntermediateSource, Target> { /** * Adds a transformation to the chain. * * @param transformation The transformation to add * * @return A TransformationConcatenator for the next transformation. */ public <IntermediateTarget> TransformationConcatenator<IntermediateTarget, Target> add(Transformation<IntermediateSource, IntermediateTarget> transformation) { transformationChain.chain.add(transformation); return new TransformationConcatenator<IntermediateTarget, Target>(); } /** * Closes the transformation chain by adding the final transformation. * * @param transformation The last transformation in the composition. * * @return The constructed composite Transformation. */ @SuppressWarnings("unchecked") public Transformation<Source,Target> last(Transformation<IntermediateSource, Target> transformation) { transformationChain.chain.add(transformation); return (Transformation<Source,Target>) transformationChain; } } /** * Contains the logic to recurse a transformation chain as created by CompositeTransformationFactory. * * @param <Source> The input type of the transformation * @param <Target> The output type of the transformation */ private class TransformationChain<Source, Target> implements Transformation<Source, Target> { // The transformation chain is stored as an ordered sequence of transformations. Type safety is ensured by the CompositeTransformationFactory. private final ArrayList<Transformation<?, ?>> chain = new ArrayList<Transformation<?, ?>>(); /** * Transforms a single input to a single output by invoking the specified transformation chain. * @param input The given input? * @return The transformed input. */ @SuppressWarnings("unchecked") // We know at construction time of the TransformationChain that the subsequent types are compatible public Target transform(Source input) throws TransformationException { Object currentInput = input; for (Transformation<?, ?> subTransformation : chain) { currentInput = new GenericTransformationWrapper(subTransformation).transform(currentInput); } return (Target)currentInput; } } }