blob: e07ae0bfc5b2e5e947f9c848a6e0a0e0a15b92a9 [file] [log] [blame]
/*
* 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.dlab.core.parser;
import com.epam.dlab.exceptions.ParseException;
import com.epam.dlab.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<String>();
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.getDlabId());
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.setDlabId(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()]));
}
}