| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.datatorrent.contrib.parser; |
| |
| import java.util.Map; |
| |
| import org.supercsv.cellprocessor.Optional; |
| import org.supercsv.cellprocessor.ParseBool; |
| import org.supercsv.cellprocessor.ParseChar; |
| import org.supercsv.cellprocessor.ParseDate; |
| import org.supercsv.cellprocessor.ParseDouble; |
| import org.supercsv.cellprocessor.ParseInt; |
| import org.supercsv.cellprocessor.ParseLong; |
| import org.supercsv.cellprocessor.constraint.DMinMax; |
| import org.supercsv.cellprocessor.constraint.Equals; |
| import org.supercsv.cellprocessor.constraint.LMinMax; |
| import org.supercsv.cellprocessor.constraint.StrMinMax; |
| import org.supercsv.cellprocessor.constraint.StrRegEx; |
| import org.supercsv.cellprocessor.constraint.Strlen; |
| import org.supercsv.cellprocessor.ift.CellProcessor; |
| import org.supercsv.cellprocessor.ift.DoubleCellProcessor; |
| import org.supercsv.cellprocessor.ift.LongCellProcessor; |
| import org.supercsv.util.CsvContext; |
| |
| import org.apache.commons.lang3.StringUtils; |
| |
| import com.datatorrent.contrib.parser.DelimitedSchema.FieldType; |
| |
| /** |
| * Helper class with methods to generate CellProcessor objects. Cell processors |
| * are an integral part of reading and writing with Super CSV - they automate |
| * the data type conversions, and enforce constraints. They implement the chain |
| * of responsibility design pattern - each processor has a single, well-defined |
| * purpose and can be chained together with other processors to fully automate |
| * all of the required conversions and constraint validation for a single |
| * delimited record. |
| * |
| * |
| * @since 3.4.0 |
| */ |
| public class CellProcessorBuilder |
| { |
| |
| /** |
| * Method to get cell processors for given field type and constraints |
| * |
| * @param fieldType |
| * data type of the field |
| * @param constraints |
| * a map of constraints |
| * @return |
| */ |
| public static CellProcessor getCellProcessor(FieldType fieldType, Map<String, Object> constraints) |
| { |
| switch (fieldType) { |
| case STRING: |
| return getStringCellProcessor(constraints); |
| case INTEGER: |
| return getIntegerCellProcessor(constraints); |
| case LONG: |
| return getLongCellProcessor(constraints); |
| case FLOAT: |
| case DOUBLE: |
| return getDoubleCellProcessor(constraints); |
| case CHARACTER: |
| return getCharCellProcessor(constraints); |
| case BOOLEAN: |
| return getBooleanCellProcessor(constraints); |
| case DATE: |
| return getDateCellProcessor(constraints); |
| default: |
| return null; |
| } |
| } |
| |
| /** |
| * Method to get cellprocessor for String with constraints. These constraints |
| * are evaluated against the String field for which this cellprocessor is |
| * defined. |
| * |
| * @param constraints |
| * map of constraints applicable to String |
| * @return CellProcessor |
| */ |
| private static CellProcessor getStringCellProcessor(Map<String, Object> constraints) |
| { |
| Boolean required = constraints.get(DelimitedSchema.REQUIRED) == null ? null : Boolean |
| .parseBoolean((String)constraints.get(DelimitedSchema.REQUIRED)); |
| Integer strLen = constraints.get(DelimitedSchema.LENGTH) == null ? null : Integer.parseInt((String)constraints |
| .get(DelimitedSchema.LENGTH)); |
| Integer minLength = constraints.get(DelimitedSchema.MIN_LENGTH) == null ? null : Integer |
| .parseInt((String)constraints.get(DelimitedSchema.MIN_LENGTH)); |
| Integer maxLength = constraints.get(DelimitedSchema.MAX_LENGTH) == null ? null : Integer |
| .parseInt((String)constraints.get(DelimitedSchema.MAX_LENGTH)); |
| String equals = constraints.get(DelimitedSchema.EQUALS) == null ? null : (String)constraints |
| .get(DelimitedSchema.EQUALS); |
| String pattern = constraints.get(DelimitedSchema.REGEX_PATTERN) == null ? null : (String)constraints |
| .get(DelimitedSchema.REGEX_PATTERN); |
| |
| CellProcessor cellProcessor = null; |
| if (StringUtils.isNotBlank(equals)) { |
| cellProcessor = new Equals(equals); |
| } else if (StringUtils.isNotBlank(pattern)) { |
| cellProcessor = new StrRegEx(pattern); |
| } else if (strLen != null) { |
| cellProcessor = new Strlen(strLen); |
| } else if (maxLength != null || minLength != null) { |
| Long min = minLength == null ? 0L : minLength; |
| Long max = maxLength == null ? LMinMax.MAX_LONG : maxLength; |
| cellProcessor = new StrMinMax(min, max); |
| } |
| if (required == null || !required) { |
| cellProcessor = addOptional(cellProcessor); |
| } |
| return cellProcessor; |
| } |
| |
| /** |
| * Method to get cellprocessor for Integer with constraints. These constraints |
| * are evaluated against the Integer field for which this cellprocessor is |
| * defined. |
| * |
| * @param constraints |
| * map of constraints applicable to Integer |
| * @return CellProcessor |
| */ |
| private static CellProcessor getIntegerCellProcessor(Map<String, Object> constraints) |
| { |
| Boolean required = constraints.get(DelimitedSchema.REQUIRED) == null ? null : Boolean |
| .parseBoolean((String)constraints.get(DelimitedSchema.REQUIRED)); |
| Integer equals = constraints.get(DelimitedSchema.EQUALS) == null ? null : Integer.parseInt((String)constraints |
| .get(DelimitedSchema.EQUALS)); |
| Integer minValue = constraints.get(DelimitedSchema.MIN_VALUE) == null ? null : Integer.parseInt((String)constraints |
| .get(DelimitedSchema.MIN_VALUE)); |
| Integer maxValue = constraints.get(DelimitedSchema.MAX_VALUE) == null ? null : Integer.parseInt((String)constraints |
| .get(DelimitedSchema.MAX_VALUE)); |
| |
| CellProcessor cellProcessor = null; |
| if (equals != null) { |
| cellProcessor = new Equals(equals); |
| cellProcessor = addParseInt(cellProcessor); |
| } else if (minValue != null || maxValue != null) { |
| cellProcessor = addIntMinMax(minValue, maxValue); |
| } else { |
| cellProcessor = addParseInt(null); |
| } |
| if (required == null || !required) { |
| cellProcessor = addOptional(cellProcessor); |
| } |
| return cellProcessor; |
| } |
| |
| /** |
| * Method to get cellprocessor for Long with constraints. These constraints |
| * are evaluated against the Long field for which this cellprocessor is |
| * defined. |
| * |
| * @param constraints |
| * map of constraints applicable to Long |
| * @return CellProcessor |
| */ |
| private static CellProcessor getLongCellProcessor(Map<String, Object> constraints) |
| { |
| Boolean required = constraints.get(DelimitedSchema.REQUIRED) == null ? null : Boolean |
| .parseBoolean((String)constraints.get(DelimitedSchema.REQUIRED)); |
| Long equals = constraints.get(DelimitedSchema.EQUALS) == null ? null : Long.parseLong((String)constraints |
| .get(DelimitedSchema.EQUALS)); |
| Long minValue = constraints.get(DelimitedSchema.MIN_VALUE) == null ? null : Long.parseLong((String)constraints |
| .get(DelimitedSchema.MIN_VALUE)); |
| Long maxValue = constraints.get(DelimitedSchema.MAX_VALUE) == null ? null : Long.parseLong((String)constraints |
| .get(DelimitedSchema.MAX_VALUE)); |
| CellProcessor cellProcessor = null; |
| if (equals != null) { |
| cellProcessor = new Equals(equals); |
| cellProcessor = addParseLong(cellProcessor); |
| } else if (minValue != null || maxValue != null) { |
| cellProcessor = addLongMinMax(minValue, maxValue); |
| } else { |
| cellProcessor = addParseLong(null); |
| } |
| if (required == null || !required) { |
| cellProcessor = addOptional(cellProcessor); |
| } |
| return cellProcessor; |
| } |
| |
| /** |
| * Method to get cellprocessor for Float/Double with constraints. These |
| * constraints are evaluated against the Float/Double field for which this |
| * cellprocessor is defined. |
| * |
| * @param constraints |
| * map of constraints applicable to Float/Double |
| * @return CellProcessor |
| */ |
| private static CellProcessor getDoubleCellProcessor(Map<String, Object> constraints) |
| { |
| Boolean required = constraints.get(DelimitedSchema.REQUIRED) == null ? null : Boolean |
| .parseBoolean((String)constraints.get(DelimitedSchema.REQUIRED)); |
| Double equals = constraints.get(DelimitedSchema.EQUALS) == null ? null : Double.parseDouble((String)constraints |
| .get(DelimitedSchema.EQUALS)); |
| Double minValue = constraints.get(DelimitedSchema.MIN_VALUE) == null ? null : Double |
| .parseDouble((String)constraints.get(DelimitedSchema.MIN_VALUE)); |
| Double maxValue = constraints.get(DelimitedSchema.MAX_VALUE) == null ? null : Double |
| .parseDouble((String)constraints.get(DelimitedSchema.MAX_VALUE)); |
| CellProcessor cellProcessor = null; |
| if (equals != null) { |
| cellProcessor = new Equals(equals); |
| cellProcessor = addParseDouble(cellProcessor); |
| } else if (minValue != null || maxValue != null) { |
| cellProcessor = addDoubleMinMax(minValue, maxValue); |
| } else { |
| cellProcessor = addParseDouble(null); |
| } |
| if (required == null || !required) { |
| cellProcessor = addOptional(cellProcessor); |
| } |
| return cellProcessor; |
| } |
| |
| /** |
| * Method to get cellprocessor for Boolean with constraints. These constraints |
| * are evaluated against the Boolean field for which this cellprocessor is |
| * defined. |
| * |
| * @param constraints |
| * map of constraints applicable to Boolean |
| * @return CellProcessor |
| */ |
| private static CellProcessor getBooleanCellProcessor(Map<String, Object> constraints) |
| { |
| Boolean required = constraints.get(DelimitedSchema.REQUIRED) == null ? null : Boolean |
| .parseBoolean((String)constraints.get(DelimitedSchema.REQUIRED)); |
| String trueValue = constraints.get(DelimitedSchema.TRUE_VALUE) == null ? null : (String)constraints |
| .get(DelimitedSchema.TRUE_VALUE); |
| String falseValue = constraints.get(DelimitedSchema.FALSE_VALUE) == null ? null : (String)constraints |
| .get(DelimitedSchema.FALSE_VALUE); |
| CellProcessor cellProcessor = null; |
| if (StringUtils.isNotBlank(trueValue) && StringUtils.isNotBlank(falseValue)) { |
| cellProcessor = new ParseBool(trueValue, falseValue); |
| } else { |
| cellProcessor = new ParseBool(); |
| } |
| if (required == null || !required) { |
| cellProcessor = addOptional(cellProcessor); |
| } |
| return cellProcessor; |
| } |
| |
| /** |
| * Method to get cellprocessor for Date with constraints. These constraints |
| * are evaluated against the Date field for which this cellprocessor is |
| * defined. |
| * |
| * @param constraints |
| * map of constraints applicable to Date |
| * @return CellProcessor |
| */ |
| private static CellProcessor getDateCellProcessor(Map<String, Object> constraints) |
| { |
| Boolean required = constraints.get(DelimitedSchema.REQUIRED) == null ? null : Boolean |
| .parseBoolean((String)constraints.get(DelimitedSchema.REQUIRED)); |
| String format = constraints.get(DelimitedSchema.DATE_FORMAT) == null ? null : (String)constraints |
| .get(DelimitedSchema.DATE_FORMAT); |
| CellProcessor cellProcessor = null; |
| String fmt = StringUtils.isNotBlank(format) ? format : "dd/MM/yyyy"; |
| cellProcessor = new ParseDate(fmt, false); |
| if (required == null || !required) { |
| cellProcessor = addOptional(cellProcessor); |
| } |
| return cellProcessor; |
| } |
| |
| /** |
| * Method to get cellprocessor for Char with constraints. These constraints |
| * are evaluated against the Char field for which this cellprocessor is |
| * defined. |
| * |
| * @param constraints |
| * map of constraints applicable to Char |
| * @return CellProcessor |
| */ |
| private static CellProcessor getCharCellProcessor(Map<String, Object> constraints) |
| { |
| Boolean required = constraints.get(DelimitedSchema.REQUIRED) == null ? null : Boolean |
| .parseBoolean((String)constraints.get(DelimitedSchema.REQUIRED)); |
| Character equals = constraints.get(DelimitedSchema.EQUALS) == null ? null : ((String)constraints |
| .get(DelimitedSchema.EQUALS)).charAt(0); |
| |
| CellProcessor cellProcessor = null; |
| if (equals != null) { |
| cellProcessor = new Equals(equals); |
| } |
| cellProcessor = addParseChar(cellProcessor); |
| if (required == null || !required) { |
| cellProcessor = addOptional(cellProcessor); |
| } |
| return cellProcessor; |
| } |
| |
| /** |
| * Get a Double Min Max cellprocessor. |
| * |
| * @param minValue |
| * minimum value. |
| * @param maxValue |
| * maximum value. |
| * @return CellProcessor |
| */ |
| private static CellProcessor addDoubleMinMax(Double minValue, Double maxValue) |
| { |
| Double min = minValue == null ? DMinMax.MIN_DOUBLE : minValue; |
| Double max = maxValue == null ? DMinMax.MAX_DOUBLE : maxValue; |
| return new DMinMax(min, max); |
| } |
| |
| /** |
| * Get a Long Min Max cellprocessor. |
| * |
| * @param minValue |
| * minimum value. |
| * @param maxValue |
| * maximum value. |
| * @return CellProcessor |
| */ |
| private static CellProcessor addLongMinMax(Long minValue, Long maxValue) |
| { |
| Long min = minValue == null ? LMinMax.MIN_LONG : minValue; |
| Long max = maxValue == null ? LMinMax.MAX_LONG : maxValue; |
| return new LMinMax(min, max); |
| } |
| |
| /** |
| * Get a Int Min Max cellprocessor. |
| * |
| * @param minValue |
| * minimum value. |
| * @param maxValue |
| * maximum value. |
| * @return CellProcessor |
| */ |
| private static CellProcessor addIntMinMax(Integer minValue, Integer maxValue) |
| { |
| Integer min = minValue == null ? Integer.MIN_VALUE : minValue; |
| Integer max = maxValue == null ? Integer.MAX_VALUE : maxValue; |
| return new IntMinMax(min, max); |
| } |
| |
| /** |
| * Get Optional cellprocessor which means field is not mandatory. |
| * |
| * @param cellProcessor |
| * next processor in the chain. |
| * @return CellProcessor |
| */ |
| private static CellProcessor addOptional(CellProcessor cellProcessor) |
| { |
| if (cellProcessor == null) { |
| return new Optional(); |
| } |
| return new Optional(cellProcessor); |
| } |
| |
| /** |
| * Get cellprocessor to parse String as Integer. |
| * |
| * @param cellProcessor |
| * next processor in the chain. |
| * @return CellProcessor |
| */ |
| private static CellProcessor addParseInt(CellProcessor cellProcessor) |
| { |
| if (cellProcessor == null) { |
| return new ParseInt(); |
| } |
| return new ParseInt((LongCellProcessor)cellProcessor); |
| } |
| |
| /** |
| * Get cellprocessor to parse String as Long. |
| * |
| * @param cellProcessor |
| * next processor in the chain. |
| * @return CellProcessor |
| */ |
| private static CellProcessor addParseLong(CellProcessor cellProcessor) |
| { |
| if (cellProcessor == null) { |
| return new ParseLong(); |
| } |
| return new ParseLong((LongCellProcessor)cellProcessor); |
| } |
| |
| /** |
| * Get cellprocessor to parse String as Double. |
| * |
| * @param cellProcessor |
| * next processor in the chain. |
| * @return CellProcessor |
| */ |
| private static CellProcessor addParseDouble(CellProcessor cellProcessor) |
| { |
| if (cellProcessor == null) { |
| return new ParseDouble(); |
| } |
| return new ParseDouble((DoubleCellProcessor)cellProcessor); |
| } |
| |
| /** |
| * Get cellprocessor to parse String as Character. |
| * |
| * @param cellProcessor |
| * next processor in the chain. |
| * @return CellProcessor |
| */ |
| private static CellProcessor addParseChar(CellProcessor cellProcessor) |
| { |
| if (cellProcessor == null) { |
| return new ParseChar(); |
| } |
| return new ParseChar((DoubleCellProcessor)cellProcessor); |
| } |
| |
| /** |
| * Custom Cell processor to handle min max constraints for Integers |
| */ |
| private static class IntMinMax extends LMinMax |
| { |
| public IntMinMax(int min, int max) |
| { |
| super(min, max); |
| } |
| |
| @Override |
| public Object execute(Object value, CsvContext context) |
| { |
| Long result = (Long)super.execute(value, context); |
| return result.intValue(); |
| } |
| } |
| |
| } |