blob: bd26f06260cac9972ce546e8b63dccfedf22418b [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.datatorrent.contrib.parser;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>
* This is schema that defines fields and their constraints for fixed width files
* The operators use this information to validate the incoming tuples.
* Information from JSON schema is saved in this object and is used by the
* operators
* <p>
* <br>
* <br>
* Example schema <br>
* <br>
* {{ "padding": " ","alignment"="left","fields": [ {"name": "adId",
* "type": "Integer","padding":"0", "length": 3} , { "name": "adName",
* "type": "String", "alignment": "right","fieldLength": 20}, { "name": "bidPrice", "type":
* "Double", "length": 5}, { "name": "startDate", "type": "Date", "length": 10,
* "format":"dd/MM/yyyy" }, { "name": "securityCode", "type": "Long","length": 10 },
* { "name": "active", "type":"Boolean","length": 2} ] }}
*
* @since 3.7.0
*/
public class FixedWidthSchema extends Schema
{
/**
* JSON key string for record length
*/
public static final String FIELD_LENGTH = "length";
/**
* JSON key string for Padding Character
*/
public static final String FIELD_PADDING_CHARACTER = "padding";
/**
* Default Padding Character
*/
public static final char DEFAULT_PADDING_CHARACTER = ' ';
/**
* Default Alignment
*/
public static final String DEFAULT_ALIGNMENT= "left";
/**
* JSON key string for Field Alignment
*/
public static final String FIELD_ALIGNMENT ="alignment";
public static final Logger logger = LoggerFactory.getLogger(FixedWidthSchema.class);
/**
* This holds list of {@link Field}
*/
private List<Field> fields = new LinkedList<>();
/**
* This holds the padding character for the entire file
*/
private char globalPadding;
/**
* This holds the global alignment
*/
private String globalAlignment;
/**
* Constructor for FixedWidthSchema
*/
public FixedWidthSchema(String json)
{
try {
initialize(json);
} catch (JSONException | IOException e) {
logger.error("{}", e);
throw new IllegalArgumentException(e);
}
}
/**
* Get the Padding character
* @return the padding character for the entire file
*/
public char getGlobalPadding()
{
return globalPadding;
}
/**
* Set the padding character
* @param padding the padding character for the entire file
*/
public void setGlobalPadding(char padding)
{
this.globalPadding = padding;
}
/**
* Get the global alignment
* @return globalAlignment the global alignment for the entire file.
*/
public String getGlobalAlignment()
{
return globalAlignment;
}
/**
* Set the global alignment
* @param globalAlignment the global alignment for the entire file
*/
public void setGlobalAlignment(String globalAlignment)
{
this.globalAlignment = globalAlignment;
}
/**
* For a given json string, this method sets the field members
*
* @param json schema as provided by the user.
*/
private void initialize(String json) throws JSONException, IOException
{
JSONObject jo = new JSONObject(json);
JSONArray fieldArray = jo.getJSONArray(FIELDS);
if (jo.has(FIELD_PADDING_CHARACTER)) {
globalPadding = jo.getString(FIELD_PADDING_CHARACTER).charAt(0);
} else {
globalPadding = DEFAULT_PADDING_CHARACTER;
}
if (jo.has(FIELD_ALIGNMENT)) {
globalAlignment = jo.getString(FIELD_ALIGNMENT);
} else {
globalAlignment = DEFAULT_ALIGNMENT;
}
for (int i = 0; i < fieldArray.length(); i++) {
JSONObject obj = fieldArray.getJSONObject(i);
Field field = new Field(obj.getString(NAME),
obj.getString(TYPE).toUpperCase(), obj.getInt(FIELD_LENGTH));
if(obj.has(FIELD_PADDING_CHARACTER)) {
field.setPadding(obj.getString(FIELD_PADDING_CHARACTER).charAt(0));
} else {
field.setPadding(globalPadding);
}
if(obj.has(FIELD_ALIGNMENT)) {
field.setAlignment(obj.getString(FIELD_ALIGNMENT));
} else {
field.setAlignment(globalAlignment);
}
//Get the format if the given data type is Date
if (field.getType() == FieldType.DATE) {
if (obj.has(DATE_FORMAT)) {
field.setDateFormat(obj.getString(DATE_FORMAT));
} else {
field.setDateFormat(DEFAULT_DATE_FORMAT);
}
}
//Get the trueValue and falseValue if the data type is Boolean
if (field.getType() == FieldType.BOOLEAN) {
if (obj.has(TRUE_VALUE)) {
field.setTrueValue(obj.getString(TRUE_VALUE));
} else {
field.setTrueValue(DEFAULT_TRUE_VALUE);
}
if (obj.has(FALSE_VALUE)) {
field.setFalseValue(obj.getString(FALSE_VALUE));
} else {
field.setFalseValue(DEFAULT_FALSE_VALUE);
}
}
fields.add(field);
fieldNames.add(field.name);
}
}
/**
* Get the list of Fields.
*
* @return fields list of {@link Field}
*/
public List<Field> getFields()
{
return Collections.unmodifiableList(fields);
}
/**
* Objects of this class represents a particular field in the schema. Each
* field has a name, type and a fieldLength.
* In case of type Date we need a dateFormat.
*
*/
public class Field extends Schema.Field
{
/**
* Length of the field
*/
private int fieldLength;
/**
* Parameter to specify format of date
*/
private String dateFormat;
/**
* Parameter to specify true value of Boolean
*/
private String trueValue;
/**
* Parameter to specify false value of Boolean
*/
private String falseValue;
/**
* Parameter to specify padding
*/
private char padding;
/**
* Parameter to specify alignment
*/
private String alignment;
/**
* Constructor for Field
* @param name - name of the field.
* @param type - type of the field.
* @param fieldLength - length of the field.
*/
public Field(String name, String type, Integer fieldLength)
{
super(name, type);
this.fieldLength = fieldLength;
this.dateFormat = DEFAULT_DATE_FORMAT;
this.trueValue = DEFAULT_TRUE_VALUE;
this.falseValue = DEFAULT_FALSE_VALUE;
this.padding=' ';
this.alignment=DEFAULT_ALIGNMENT;
}
/**
* Get the Length of the Field
* @return fieldLength length of the field.
*/
public int getFieldLength()
{
return fieldLength;
}
/**
* Set the end pointer of the field
*
* @param fieldLength length of the field.
*/
public void setFieldLength(Integer fieldLength)
{
this.fieldLength = fieldLength;
}
/**
* Get the dateFormat of the field
*
* @return dateFormat format of date given.
*/
public String getDateFormat()
{
return dateFormat;
}
/**
* Set the the dateFormat of the field
*
* @param dateFormat sets the format of date.
*/
public void setDateFormat(String dateFormat)
{
this.dateFormat = dateFormat;
}
/**
* Get the trueValue of the Boolean field
* @return trueValue gets the equivalent true value.
*/
public String getTrueValue()
{
return trueValue;
}
/**
* Set the trueValue of the Boolean field
*
* @param trueValue sets the equivalent true value.
*/
public void setTrueValue(String trueValue)
{
this.trueValue = trueValue;
}
/**
* Get the falseValue of the Boolean field
* @return falseValue gets the equivalent false value.
*/
public String getFalseValue()
{
return falseValue;
}
/**
* Set the end pointer of the field
*
* @param falseValue sets the equivalent false value.
*/
public void setFalseValue(String falseValue)
{
this.falseValue = falseValue;
}
/**
* Get the field padding
* @return padding gets the padding for the individual field.
*/
public char getPadding()
{
return padding;
}
/**
* Set the field padding
* @param padding sets the padding for the individual field.
*/
public void setPadding(char padding)
{
this.padding = padding;
}
/**
* Get the field alignment
* @return alignment gets the alignment for the individual field.
*/
public String getAlignment()
{
return alignment;
}
/**
* Set the field alignment
* @param alignment sets the alignment for the individual field.
*/
public void setAlignment(String alignment)
{
this.alignment = alignment;
}
@Override
public String toString()
{
return "Fields [name=" + name + ", type=" + type + " fieldLength= " + fieldLength + "]";
}
}
}