All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geolatte.common.transformer.DefaultTransformer Maven / Gradle / Ivy

Go to download

This GeoLatte-common library contains the transformer framework and other common classes used by other GeoLatte modules.

There is a newer version: 0.8
Show newest version
/*
 * 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 .
 *
 * 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.Iterator;
import java.util.NoSuchElementException;

/**
 * Transforms a collection of input elements to a collection of output elements, using a {@link Transformation} to
 * process each element.
 *
 * Once the input is set (setInput()), output() may be called to get an iterator to set the transformation process in
 * motion. output() will return the same iterable/iterator as long as the input remains the same. This means that one
 * cannot transform the input element multiple times in parallel.
 * 

* e.g., *

 * {@code
 * setInput(input);
 * iter = output().iterator();
 * iter.next();                // -> object#1
 * output().iterator().next(); // -> object#2 (the iterator is the same)
 * setInput(otherInput);
 * output().iterator().next(); // -> object#a
 * iter.next();                // -> object#3 (the original iterator/transformation can still be used)
 * }
 * 
* * @author Bert Vanhooff * @author Qmino bvba * @param The type of the elements that will be transformed. * @param The type of the transformed elements. *

*

* Creation-Date: 18-Mar-2010
* Creation-Time: 16:30:04
*

* @since SDK1.5 */ public class DefaultTransformer extends AbstractObservableTransformer { // One of the two transformations below will be filled in private Transformation transformation; private OneToManyTransformation oneToManyTransformation; private Iterable currentInput; // The currentInput Iterable set by the client private Iterable currentOutput; /** * Constructs a DefaultTransformer which calls the given transformation. * * @param transformation Cannot be null * @throws IllegalArgumentException When transformation is null. */ public DefaultTransformer(Transformation transformation) { if (transformation == null) throw new IllegalArgumentException("Argument transformation cannot be null"); this.transformation = transformation; } /** * Constructs a DefaultTransformer which calls the given transformation. Using a one-to-many transformation means * that for each input element, 0 to x output elements are produced. * * @param transformation Cannot be null * @throws IllegalArgumentException When transformation is null. */ public DefaultTransformer(OneToManyTransformation transformation) { if (transformation == null) throw new IllegalArgumentException("Argument transformation cannot be null"); this.oneToManyTransformation = transformation; } /** * {@inheritDoc} */ @Override protected void setInput(Iterable input) { currentInput = input; currentOutput = null; } /** * {@inheritDoc} */ @Override protected Iterable output() { if (currentInput == null && currentOutput == null) return null; // In case a transformation is already in progress, return the existing output iterable if (currentOutput != null) return currentOutput; // No transformation is in progress -> create new output and forget the input currentOutput = new DefaultTransformerIterable(currentInput.iterator()); currentInput = null; return currentOutput; } /* * Implementation of the actual transformer process is encapsulated in an internal Iterator. */ /** * The Iterable implementation for DefaultTransformer. Returns the DefaultTransformerIterator. * * @param Target type that must correspond to the Target type of the corresponding transformer. */ private class DefaultTransformerIterable implements Iterable { private Iterator inputIterator; private DefaultTransformerIterable(Iterator inputIterator) { this.inputIterator = inputIterator; } /** * Returns an iterator for the Transformer. * * @return An iterator for the Transformer. */ public Iterator iterator() { if (transformation != null) { return new DefaultTransformerIterator(inputIterator); } else if (oneToManyTransformation != null) { return new DefaultOneToManyTransformerIterator(inputIterator); } return null; } } /** * The Iterator implementation that delegates to DefaultTransformer to get its next value. * * @param Target type that must correspond to the Target type of the corresponding transformer. */ private class DefaultTransformerIterator implements Iterator { private Iterator inputIterator; // The next transformed element private Target cachedElement = null; private boolean isCachedElementValid = false; private DefaultTransformerIterator(Iterator inputIterator) { this.inputIterator = inputIterator; } /** * Returns true if the transformation can produce more elements. (In other * words, returns true if next would return an element * rather than throwing an exception.) * * @return true if the transformation can produce more elements. */ @SuppressWarnings("unchecked") public boolean hasNext() { if (isCachedElementValid) return true; while (inputIterator.hasNext()) { Source nextElement = null; try { nextElement = inputIterator.next(); // Don't know why this cast is actually necassary cachedElement = (Target) transformation.transform(nextElement); isCachedElementValid = true; return true; } catch (TransformationException e) { onTransformerErrorOccurred(nextElement, e); } } return false; } /** * Returns the next transformed element. * * @return The next transformed element. */ public Target next() { if (isCachedElementValid || hasNext()) { isCachedElementValid = false; return cachedElement; } throw new NoSuchElementException(); } /** * Not supported. */ public void remove() { throw new UnsupportedOperationException(); } } /** * The Iterator implementation that delegates to DefaultTransformer to get its next value. * * @param Target type that must correspond to the Target type of the corresponding transformer. */ private class DefaultOneToManyTransformerIterator implements Iterator { private Iterator inputIterator; private Iterator currentTargetIterator; private DefaultOneToManyTransformerIterator(Iterator inputIterator) { this.inputIterator = inputIterator; currentTargetIterator = new Iterator() { public boolean hasNext() { return false; } public Target next() { throw new NoSuchElementException(); } public void remove() { throw new UnsupportedOperationException(); } }; } /** * Returns true if the transformation can produce more elements. (In other * words, returns true if next would return an element * rather than throwing an exception.) * * @return true if the transformation can produce more elements. */ @SuppressWarnings("unchecked") public boolean hasNext() { // If the current 'one-to-many transformation iterator' still has elements, true if (currentTargetIterator.hasNext()) return true; // Else go to next input element to get the next 'one-to-many transformation iterator' while (inputIterator.hasNext()) { Source nextElement = null; try { nextElement = inputIterator.next(); // Don't know why this cast is actually necassary currentTargetIterator = (Iterator) oneToManyTransformation.transform(nextElement); if (currentTargetIterator.hasNext()) { // if this iterator has elements, ok, else continue return true; } } catch (TransformationException e) { onTransformerErrorOccurred(nextElement, e); } } return false; } /** * Returns the next transformed element. * * @return The next transformed element. */ public Target next() { if (currentTargetIterator.hasNext()) { return currentTargetIterator.next(); } throw new NoSuchElementException(); } /** * Not supported. */ public void remove() { throw new UnsupportedOperationException(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy