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

com.cinchapi.etl.CompositeTransformer Maven / Gradle / Ivy

/*
 * Copyright (c) 2013-2017 Cinchapi Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.cinchapi.etl;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable;

import com.cinchapi.common.collect.AnyMaps;
import com.cinchapi.common.collect.MergeStrategies;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

/**
 * A {@link Transformer} that is composed of other {@link Transformer
 * Transformers}.
 * 

* Each of the composing Transformers is applied in declaration order. *

* * @author Jeff Nelson */ class CompositeTransformer implements Transformer { /** * Apply the {@code transformer} to each key/value mapping within the * {@code object}. While doing so, use the {@code current} transformation * mapping as a merge source. * * @param transformer * @param object * @param next an optional collection that tracks the future state of the * {@code object} after applying the {@code transformer} to each * key/value mapping * @return the transformed object after applying the {@code transformer} and * merging with the {@code current} */ private static Map transformAndMerge( Transformer transformer, Map object, @Nullable Map next) { for (Entry entry : object.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); Map transformed = transformer.transform(key, value); if(next == null && transformed != null) { // The current key/value pair is the first to result in a // non-null transformation, so we have to go back and // re-transform the entire object to preserve all the // non-transformed data alongside the result of transforming the // current key/value pair. next = transformAndMerge(transformer, object, Maps.newLinkedHashMap()); } else if(next != null) { AnyMaps.mergeInPlace(next, transformed == null ? ImmutableMap.of(key, value) : transformed, MergeStrategies::theirs); } } return next; } /** * An ordered list of the {@link Transformer transformers} that are applied * in the composite {@link #transform(String, String)} method */ private final List transformers; /** * Construct a new instance. * * @param transformers */ public CompositeTransformer(List transformers) { Preconditions.checkArgument(!transformers.isEmpty()); this.transformers = ImmutableList.copyOf(transformers); } /** * {@inheritDoc} *

* NOTE: This {@link Transformer} users a breadth-first strategy where a * composed transformer is applied to the entire {@code object} before the * next one. *

*/ @Override @Nullable public Map transform(Map object) { for (Transformer transformer : transformers) { object = MoreObjects.firstNonNull(transformer.transform(object), object); } return object; } @Override @Nullable public Map transform(String key, Object value) { Map transformed = null; for (Transformer transformer : transformers) { Map next = null; if(transformed == null) { // Either this is the first attempt to transform key/value or // all other previous attempts have declined to do so. next = transformer.transform(key, value); } else { // The original key/value, at some point, has been transformed // so we must go through the entire map and apply the // transformer in order to get the #next state. next = transformAndMerge(transformer, transformed, null); } if(next != null) { // NOTE: We replace #transformed with #next (instead of // merging) because the composition is supposed to be a // successive operation instead of a cumulative one. transformed = next; } } return transformed; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy