| /* |
| * 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.epam.datalab.core.parser; |
| |
| import com.epam.datalab.exceptions.ParseException; |
| import com.epam.datalab.model.aws.ReportLine; |
| import org.apache.commons.lang3.StringUtils; |
| |
| import java.text.DecimalFormat; |
| import java.text.DecimalFormatSymbols; |
| import java.util.ArrayList; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| |
| /** |
| * Provides common format features. |
| */ |
| public class CommonFormat { |
| /** |
| * Character for separate field names and values. |
| */ |
| public static final char FIELD_SEPARATOR = ','; |
| |
| /** |
| * Character for termination field names and values. |
| */ |
| public static final char FIELD_DELIMITER = '"'; |
| |
| /** |
| * Escape character. |
| */ |
| public static final char ESCAPE_CHAR = '\\'; |
| |
| /** |
| * Default character used for decimal sign. |
| */ |
| public static final char DECIMAL_SEPARATOR_DEFAULT = '.'; |
| |
| /** |
| * Default character used for thousands separator. |
| */ |
| public static final char DECIMAL_GROUPING_SEPARATOR_DEFAULT = ' '; |
| |
| /** |
| * String of the field separator for replacement to target data. |
| */ |
| private static final String DELIMITER_REPLACE_FROM = String.valueOf(FIELD_DELIMITER); |
| |
| /** |
| * String of the escaped field separator for replacement to target data. |
| */ |
| private static final String DELIMITER_REPLACE_TO = new StringBuilder() |
| .append(ESCAPE_CHAR) |
| .append(FIELD_DELIMITER) |
| .toString(); |
| |
| /** |
| * Formatter for convert decimal numbers to string. |
| */ |
| private static final DecimalFormat DECIMAL_TO_STRING_FORMAT; |
| |
| static { |
| DECIMAL_TO_STRING_FORMAT = new DecimalFormat(); |
| DecimalFormatSymbols symbols = new DecimalFormatSymbols(); |
| symbols.setDecimalSeparator(DECIMAL_SEPARATOR_DEFAULT); |
| DECIMAL_TO_STRING_FORMAT.setDecimalFormatSymbols(symbols); |
| DECIMAL_TO_STRING_FORMAT.setGroupingUsed(false); |
| DECIMAL_TO_STRING_FORMAT.setMaximumFractionDigits(100); |
| } |
| |
| |
| /** |
| * Column meta information. |
| */ |
| private final ColumnMeta columnMeta; |
| |
| /** |
| * Formatter for parse of decimal number . |
| */ |
| private final DecimalFormat sourceDecimalFormat; |
| |
| |
| /** |
| * Instantiate the helper for common format. |
| * |
| * @param columnMeta column meta information. |
| */ |
| public CommonFormat(ColumnMeta columnMeta) { |
| this(columnMeta, DECIMAL_SEPARATOR_DEFAULT, DECIMAL_GROUPING_SEPARATOR_DEFAULT); |
| } |
| |
| /** |
| * Instantiate the helper for common format. |
| * |
| * @param columnMeta column meta information. |
| * @param decimalSeparator the character used for decimal sign. |
| * @param groupingSeparator the character used for thousands separator. |
| */ |
| public CommonFormat(ColumnMeta columnMeta, char sourceDecimalSeparator, char sourceGroupingSeparator) { |
| this.columnMeta = columnMeta; |
| this.sourceDecimalFormat = getDecimalFormat(sourceDecimalSeparator, sourceGroupingSeparator); |
| } |
| |
| |
| /** |
| * Create and return the target row for common format from source. |
| * |
| * @param sourceRow the source row. |
| * @return row in common format. |
| * @throws ParseException |
| */ |
| public ReportLine toCommonFormat(List<String> sourceRow) throws ParseException { |
| if (columnMeta.getColumnMapping() == null) { |
| return toReportLine(sourceRow); |
| } |
| |
| List<String> targetRow = new ArrayList<>(); |
| for (ColumnInfo columnInfo : columnMeta.getColumnMapping()) { |
| targetRow.add((columnInfo.sourceIndex < 0 ? "" : |
| (columnInfo.sourceIndex < sourceRow.size() ? sourceRow.get(columnInfo.sourceIndex) : null))); |
| } |
| return toReportLine(targetRow); |
| } |
| |
| /** |
| * Add the column value to string in CSV format. |
| * |
| * @param sb the buffer of sting. |
| * @param value the value. |
| * @return the buffer of string. |
| */ |
| private static StringBuilder addToStringBuilder(StringBuilder sb, String value) { |
| if (sb.length() > 0) { |
| sb.append(FIELD_SEPARATOR); |
| } |
| return sb.append(FIELD_DELIMITER) |
| .append(StringUtils.replace(value, DELIMITER_REPLACE_FROM, DELIMITER_REPLACE_TO)) |
| .append(FIELD_DELIMITER); |
| } |
| |
| /** |
| * Convert row to line in CSV format. |
| * |
| * @param row row for convertation. |
| * @return string in CSV format. |
| */ |
| public static String rowToString(List<String> row) { |
| StringBuilder sb = new StringBuilder(); |
| for (String s : row) { |
| addToStringBuilder(sb, s); |
| } |
| return sb.toString(); |
| } |
| |
| /** |
| * Convert row to line in CSV format. |
| * |
| * @param row row for convertation. |
| * @return string in CSV format. |
| */ |
| public static String rowToString(ReportLine row) { |
| StringBuilder sb = new StringBuilder(); |
| |
| addToStringBuilder(sb, row.getDatalabId()); |
| addToStringBuilder(sb, row.getUser()); |
| addToStringBuilder(sb, row.getUsageDate()); |
| addToStringBuilder(sb, row.getProduct()); |
| addToStringBuilder(sb, row.getUsageType()); |
| addToStringBuilder(sb, doubleToString(row.getUsage())); |
| addToStringBuilder(sb, doubleToString(row.getCost())); |
| addToStringBuilder(sb, row.getCurrencyCode()); |
| addToStringBuilder(sb, row.getResourceType().toString()); |
| addToStringBuilder(sb, row.getResourceId()); |
| |
| if (row.getTags() != null) { |
| for (String key : row.getTags().keySet()) { |
| addToStringBuilder(sb, row.getTags().get(key)); |
| } |
| } |
| return sb.toString(); |
| } |
| |
| /** |
| * Create and return decimal formatter. |
| * |
| * @param decimalSeparator the character used for decimal sign. |
| * @param groupingSeparator the character used for thousands separator. |
| * @return Formatter for decimal digits. |
| */ |
| private DecimalFormat getDecimalFormat(char decimalSeparator, char groupingSeparator) { |
| DecimalFormat df = new DecimalFormat(); |
| DecimalFormatSymbols symbols = new DecimalFormatSymbols(); |
| symbols.setDecimalSeparator(decimalSeparator); |
| symbols.setGroupingSeparator(groupingSeparator); |
| df.setDecimalFormatSymbols(symbols); |
| return df; |
| } |
| |
| /** |
| * Parse and return double value. If value is <b>null</b> or empty return zero. |
| * |
| * @param columnName the name of column. |
| * @param value the value. |
| * @throws ParseException |
| */ |
| public double parseDouble(String columnName, String value) throws ParseException { |
| if (value == null || value.trim().isEmpty()) { |
| return 0; |
| } |
| try { |
| return sourceDecimalFormat.parse(value).doubleValue(); |
| } catch (Exception e) { |
| throw new ParseException("Cannot cast column " + columnName + " value \"" + value + "\" to double: " + e |
| .getLocalizedMessage(), e); |
| } |
| } |
| |
| /** |
| * Return the string representation of double value. |
| * |
| * @param value the value. |
| */ |
| public static String doubleToString(double value) { |
| return DECIMAL_TO_STRING_FORMAT.format(value); |
| } |
| |
| /** |
| * Creates and returns the line of billing report from the list of values. |
| * |
| * @param row the list of values. |
| * @return the line of billing report. |
| * @throws ParseException |
| */ |
| public ReportLine toReportLine(List<String> row) throws ParseException { |
| if (row.size() < ColumnMeta.TAG_COLUMN_INDEX || row.size() > columnMeta.getTargetColumnNames().size()) { |
| throw new ParseException("Invalid the number of columns in list: expected from " + ColumnMeta |
| .TAG_COLUMN_INDEX + |
| " to " + columnMeta.getTargetColumnNames().size() + ", actual " + row.size()); |
| } |
| ReportLine line = new ReportLine(); |
| int i = 0; |
| |
| line.setDatalabId(row.get(i)); |
| line.setUser(row.get(++i)); |
| line.setUsageDate(row.get(++i)); |
| line.setProduct(row.get(++i)); |
| line.setUsageType(row.get(++i)); |
| line.setUsage(parseDouble("usage", row.get(++i))); |
| line.setCost(parseDouble("cost", row.get(++i))); |
| line.setCurrencyCode(row.get(++i)); |
| line.setResourceTypeId(row.get(++i)); |
| |
| if (row.size() >= ColumnMeta.TAG_COLUMN_INDEX) { |
| LinkedHashMap<String, String> tags = new LinkedHashMap<>(); |
| i++; |
| while (i < row.size()) { |
| tags.put(columnMeta.getTargetColumnNames().get(i), row.get(i++)); |
| } |
| line.setTags(tags); |
| } |
| |
| return line; |
| } |
| |
| |
| /** |
| * Print row to console. |
| * |
| * @param row array of values. |
| */ |
| public static void printRow(String[] row) { |
| System.out.print(" | "); |
| for (String s : row) { |
| System.out.print(s + " | "); |
| } |
| System.out.println(); |
| } |
| |
| /** |
| * Print row to console. |
| * |
| * @param row list of values. |
| */ |
| public static void printRow(List<String> row) { |
| printRow(row.toArray(new String[row.size()])); |
| } |
| } |