package com.revolsys.gis.parallel; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.function.Predicate; import org.springframework.core.convert.converter.Converter; import com.revolsys.gis.converter.FilterRecordConverter; import com.revolsys.gis.converter.SimpleRecordConveter; import com.revolsys.gis.converter.process.CopyValues; import com.revolsys.logging.Logs; import com.revolsys.parallel.channel.Channel; import com.revolsys.parallel.process.BaseInOutProcess; import com.revolsys.record.Record; import com.revolsys.record.schema.RecordDefinition; import com.revolsys.record.schema.RecordDefinitionFactory; import com.revolsys.util.count.LabelCountMap; public class RecordConverterProcess extends BaseInOutProcess<Record, Record> { private Converter<Record, Record> defaultConverter; private Map<Object, Map<String, Object>> simpleMapping; private LabelCountMap labelCountMap = new LabelCountMap("Converted"); private RecordDefinitionFactory targetRecordDefinitionFactory; private Map<String, Converter<Record, Record>> typeConverterMap = new HashMap<>(); private Map<String, Collection<FilterRecordConverter>> typeFilterConverterMap = new LinkedHashMap<>(); // // private LabelCountMap ignoredStatistics = new LabelCountMap("Ignored"); public void addTypeConverter(final String typePath, final Converter<Record, Record> converter) { this.typeConverterMap.put(typePath, converter); } public void addTypeFilterConverter(final String typePath, final FilterRecordConverter filterConverter) { Collection<FilterRecordConverter> converters = this.typeFilterConverterMap.get(typePath); if (converters == null) { converters = new ArrayList<>(); this.typeFilterConverterMap.put(typePath, converters); } converters.add(filterConverter); } protected Record convert(final Record source) { int matchCount = 0; final RecordDefinition sourceRecordDefinition = source.getRecordDefinition(); final String sourceTypeName = sourceRecordDefinition.getPath(); final Collection<FilterRecordConverter> converters = this.typeFilterConverterMap .get(sourceTypeName); Record target = null; if (converters != null && !converters.isEmpty()) { for (final FilterRecordConverter filterConverter : converters) { final Predicate<Record> filter = filterConverter.getFilter(); if (filter.test(source)) { final Converter<Record, Record> converter = filterConverter.getConverter(); target = converter.convert(source); matchCount++; } } if (matchCount == 1) { return target; } } if (matchCount == 0) { final Converter<Record, Record> typeConveter = this.typeConverterMap.get(sourceTypeName); if (typeConveter != null) { target = typeConveter.convert(source); return target; } else if (this.defaultConverter == null) { return convertObjectWithNoConverter(source); } else { return this.defaultConverter.convert(source); } } else { final StringBuilder sb = new StringBuilder("Multiple conveters found: \n "); for (final FilterRecordConverter filterConverter : converters) { final Predicate<Record> filter = filterConverter.getFilter(); if (filter.test(source)) { sb.append(filter.toString()); sb.append("\n "); } } sb.append(source); Logs.error(this, sb.toString()); return null; } } protected Record convertObjectWithNoConverter(final Record source) { Logs.error(this, "No converter found for: " + source); return null; } public Converter<Record, Record> getDefaultConverter() { return this.defaultConverter; } public Map<String, Collection<FilterRecordConverter>> getFilterTypeConverterMap() { return this.typeFilterConverterMap; } public LabelCountMap getStatistics() { return this.labelCountMap; } public RecordDefinition getTargetRecordDefinition(final String typePath) { return this.targetRecordDefinitionFactory.getRecordDefinition(typePath); } public RecordDefinitionFactory getTargetRecordDefinitionFactory() { return this.targetRecordDefinitionFactory; } public Map<String, Converter<Record, Record>> getTypeConverterMap() { return this.typeConverterMap; } @Override protected void postRun(final Channel<Record> in, final Channel<Record> out) { super.postRun(in, out); this.labelCountMap.disconnect(); // ignoredStatistics.disconnect(); } @Override protected void preRun(final Channel<Record> in, final Channel<Record> out) { this.labelCountMap.connect(); // ignoredStatistics.connect(); if (this.simpleMapping != null) { for (final Entry<Object, Map<String, Object>> entry : this.simpleMapping.entrySet()) { final Object key = entry.getKey(); String sourceTypeName; if (key instanceof String) { sourceTypeName = (String)key; } else { sourceTypeName = String.valueOf(key.toString()); } final Map<String, Object> map = entry.getValue(); final Object targetName = map.get("typePath"); String targetTypeName; if (key instanceof String) { targetTypeName = (String)targetName; } else { targetTypeName = String.valueOf(targetName.toString()); } @SuppressWarnings("unchecked") final Map<String, String> attributeMapping = (Map<String, String>)map .get("attributeMapping"); final RecordDefinition targetRecordDefinition = getTargetRecordDefinition(targetTypeName); final SimpleRecordConveter converter = new SimpleRecordConveter(targetRecordDefinition); converter.addProcessor(new CopyValues(attributeMapping)); addTypeConverter(sourceTypeName, converter); } } } @Override protected void process(final Channel<Record> in, final Channel<Record> out, final Record source) { final Record target = convert(source); if (target == null) { // ignoredStatistics.add(source); } else { out.write(target); if (source != target) { this.labelCountMap.addCount(target); } } } public void setDefaultConverter(final Converter<Record, Record> defaultConverter) { this.defaultConverter = defaultConverter; } public void setSimpleMapping(final Map<Object, Map<String, Object>> simpleMapping) { this.simpleMapping = simpleMapping; } public void setStatistics(final LabelCountMap labelCountMap) { if (this.labelCountMap != labelCountMap) { this.labelCountMap = labelCountMap; labelCountMap.connect(); } } public void setTargetRecordDefinitionFactory( final RecordDefinitionFactory targetRecordDefinitionFactory) { this.targetRecordDefinitionFactory = targetRecordDefinitionFactory; } public void setTypeConverterMap(final Map<String, Converter<Record, Record>> typeConverterMap) { this.typeConverterMap = typeConverterMap; } public void setTypeFilterConverterMap( final Map<String, Collection<FilterRecordConverter>> typeConverterMap) { this.typeFilterConverterMap = typeConverterMap; } }