package org.finra.datagenerator.scaffolding.transformer.service; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Lists; import org.finra.datagenerator.scaffolding.random.core.RubberRandom; import org.finra.datagenerator.scaffolding.random.core.RubberRandomImpl; import org.finra.datagenerator.scaffolding.transformer.function.FunctionTransformation; import org.finra.datagenerator.scaffolding.transformer.service.transformations.TransformationsImpl; import org.finra.datagenerator.scaffolding.transformer.utils.TransformerUtils; import org.finra.datagenerator.scaffolding.utils.ClassUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.LongStream; /** * Created by dkopel on 11/17/16. */ @Service public class MultiTransformer implements MultiTransformerService { private final Logger logger = LoggerFactory.getLogger(getClass()); private RubberRandom rubberRandom; private final ObjectMapper objectMapper; private final TransformerService transformerService; private final TransformationSessionType defaultSessionType = TransformationSessionType.MERGE; private final String defaultBasePackage = "org.finra.datagenerator.scaffolding.transformer"; private final Set<Class<? extends FunctionTransformation>> functionTransformerClasses = new HashSet(); private final Set<FunctionTransformationContainer> functionTransformers = new HashSet(); @Autowired(required = false) public MultiTransformer(RubberRandom rubberRandom, ObjectMapper objectMapper, TransformerService transformerService) { this.rubberRandom = rubberRandom; this.objectMapper = objectMapper; this.transformerService = transformerService; scan(defaultBasePackage); } public MultiTransformer() { this.rubberRandom = RubberRandomImpl.apply(); this.objectMapper = new ObjectMapper(); //this.transformerService = new Transformer(randomProvider, objectMapper); //this.transformerService = new TransformerPlus(); this.transformerService = null; scan(defaultBasePackage); } @Override public void scan(String basePackage) { functionTransformerClasses.addAll(TransformerUtils.findFunctionTransformers(basePackage)); functionTransformerClasses.forEach(ftc -> { try { defaultTransformer(ftc); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } }); } private <V extends FunctionTransformation<V>> FunctionTransformationContainer<V> defaultTransformer(Class<? extends V> clazz) throws IllegalAccessException, InstantiationException { V inst = clazz.newInstance(); FunctionTransformationContainer container = new FunctionTransformationContainer<V>("default", clazz, inst); this.functionTransformers.add(container); return container; } @Override public <V extends FunctionTransformation> List<FunctionTransformationContainer<V>> getFunctionTransformation(Class<V> clazz) { List fct = functionTransformers.stream().filter(fc -> fc.clazz.equals(clazz)).collect(Collectors.toList()); if(fct.size() > 0) { return fct; } else if(functionTransformerClasses.contains(clazz)) { try { return Lists.newArrayList(defaultTransformer(clazz)); } catch(Exception e) { throw new IllegalStateException("Unable to instantiate the function transformation with class "+clazz); } } else { throw new IllegalArgumentException("A class with that name that implements the FunctionTransformation interface cannot be found on the classpath."); } } @Override public <V extends FunctionTransformation> FunctionTransformationContainer<V> getFunctionTransformation(String key, Class<V> clazz) { List<FunctionTransformationContainer<V>> cs = functionTransformers.stream() .filter(ft -> ft.key.equals(key) && ft.clazz.equals(clazz)) .map(ft -> (FunctionTransformationContainer<V>) ft) .collect(Collectors.toList()); if(cs.size() > 0) { return cs.iterator().next(); } throw new NoSuchElementException(); } @Override public <V extends FunctionTransformation> void setFunctionTransformation(String key, Class<V> clazz) { setFunctionTransformation(key, clazz, new Object[]{}, new Class[]{}); } @Override public <V extends FunctionTransformation> void setFunctionTransformation(String key, Class<V> clazz, Object[] args, Class[] argClasses) { V in = null; if(functionTransformerClasses.contains(clazz)) { logger.debug("Have the arguments: {} with classes {}", args, argClasses); try { in = ClassUtils.createNewInstance(clazz, args, argClasses); } catch (InstantiationException e) { e.printStackTrace(); } } else { try { in = clazz.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } functionTransformers.add(new FunctionTransformationContainer<V>(key, clazz, in)); } @Override public void registerTransformations(Set<TransformationsImpl> transformations) { transformerService.registerTransformations(transformations); } @Override public <T> Map<Long, ? extends Collection<TransformationContainer>> orderedTransform(Map<Long, List<TransformationContainer>> containers, Long iterations) { return orderedTransform(containers, iterations, new HashMap<>()); } @Override public <T> Map<Long, ? extends Collection<TransformationContainer>> orderedTransform(Map<Long, List<TransformationContainer>> containers, Long iterations, Map<Predicate<TransformationContext>, Set<OutputOverride<?>>> overrides) { final Map<Long, Collection<TransformationContainer>> nc = TransformationContext.convert(containers); LongStream.range(0, iterations).forEachOrdered(current -> { logger.debug("Invoking transformation #{}", current); transformerService.transform( new TransformationContext( current, nc, functionTransformers, defaultSessionType, overrides ) ); }); return nc; } }