/*******************************************************************************
* Copyright 2017 Capital One Services, LLC and Bitwise, Inc.
* Licensed 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 hydrograph.engine.cascading.assembly.handlers;
import cascading.tuple.Fields;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class FieldManupulatingHandler implements Serializable {
/**
*
*/
private static final long serialVersionUID = -8968542678313899309L;
protected ArrayList<Fields> operationInputFields;
protected ArrayList<Fields> operationOutputFields;
protected Fields passThrough;
protected Fields keyFields;
protected Fields mapSourceFields;
protected Fields mapTargetFields;
private Fields outputFields;
protected Map<String, String> mapFields;
private ArrayList<int[]> outputPositions;
private Fields inputFields = new Fields();
private Fields outputOperationFields = new Fields();
private int[] inputPassThorughPositions;
private int[] outputPassThorughPositions;
private int[] mapSourceFieldPositions;
private int[] mapTargetFieldPositions;
private ArrayList<int[]> inputPositions;
private int[] operationFieldsPositions;
public FieldManupulatingHandler(Fields inputFields, Fields outputFields,
Fields keyFields, Fields passThrough, Map<String, String> mapFields) {
this.operationInputFields = new ArrayList<Fields>();
this.operationOutputFields = new ArrayList<Fields>();
this.operationInputFields.add(inputFields);
this.operationOutputFields.add(outputFields);
this.passThrough = passThrough;
this.keyFields = keyFields;
this.mapFields = mapFields;
extractMapSourceAndTargetFields();
determineIO();
determineFieldPositions();
}
public FieldManupulatingHandler(ArrayList<Fields> operationInputFields,
ArrayList<Fields> operationOutputFields, Fields passThrough,
Map<String, String> mapFields, Fields operationFields) {
this(operationInputFields, operationOutputFields, null, passThrough,
mapFields, operationFields);
}
public FieldManupulatingHandler(ArrayList<Fields> operationInputFields,
ArrayList<Fields> operationOutputFields, Fields passThrough) {
this(operationInputFields, operationOutputFields, null, passThrough,
null, null);
}
public FieldManupulatingHandler(ArrayList<Fields> operationInputFields,
ArrayList<Fields> operationOutputFields, Fields passThrough,
Fields operationFields) {
this(operationInputFields, operationOutputFields, null, passThrough,
null, operationFields);
}
public FieldManupulatingHandler(ArrayList<Fields> operationInputFields,
ArrayList<Fields> operationOutputFields, Fields keyFields,
Fields passThrough, Map<String, String> mapFields,
Fields operationFields) {
this.operationInputFields = operationInputFields;
this.operationOutputFields = operationOutputFields;
this.passThrough = passThrough;
this.keyFields = keyFields;
this.mapFields = mapFields;
this.outputFields = operationFields;
extractMapSourceAndTargetFields();
determineIO();
determineFieldPositions();
}
/**
* Extracts the source fields & target fields from the {@code mapFields}
* {@code HashMap} and stores them into {@code mapSourceFields} &
* {@code mapTargetFields} object respectively
*/
private void extractMapSourceAndTargetFields() {
ArrayList<String> mapSourceFieldsList = new ArrayList<String>();
ArrayList<String> mapTargetFieldsList = new ArrayList<String>();
for (String key : mapFields.keySet()) {
mapSourceFieldsList.add(key);
mapTargetFieldsList.add(mapFields.get(key));
}
if (mapSourceFields == null) {
mapSourceFields = new Fields(
mapSourceFieldsList.toArray(new String[mapSourceFieldsList
.size()]));
} else {
mapSourceFields.append(new Fields(mapSourceFieldsList
.toArray(new String[mapSourceFieldsList.size()])));
}
if (mapTargetFields == null) {
mapTargetFields = new Fields(
mapTargetFieldsList.toArray(new String[mapTargetFieldsList
.size()]));
} else {
mapTargetFields.append(new Fields(mapTargetFieldsList
.toArray(new String[mapTargetFieldsList.size()])));
}
}
private void determineIO() {
if (operationInputFields != null && operationInputFields.size() > 0) {
inputFields = Fields.merge(operationInputFields
.toArray(new Fields[operationInputFields.size()]));
}
if (operationOutputFields != null && operationOutputFields.size() > 0) {
outputOperationFields = Fields.merge(operationOutputFields
.toArray(new Fields[operationOutputFields.size()]));
}
if (keyFields != null) {
inputFields = Fields.merge(inputFields, keyFields);
}
if (mapSourceFields != null) {
inputFields = Fields.merge(inputFields, mapSourceFields);
}
if (mapTargetFields != null) {
outputOperationFields = Fields.merge(outputOperationFields, mapTargetFields);
outputFields = Fields.merge(outputFields, mapTargetFields);
}
if (passThrough != null) {
outputFields = Fields.merge(outputFields, passThrough);
inputFields = Fields.merge(inputFields, passThrough);
outputOperationFields = Fields.merge(outputOperationFields, passThrough);
}
}
private void determineFieldPositions() {
inputPositions = new ArrayList<int[]>();
if (operationInputFields != null) {
for (Fields fields : operationInputFields) {
inputPositions.add(getInputFields().getPos(fields));
}
}
if (outputFields != null) {
operationFieldsPositions = getOutputFields().getPos(
outputFields);
} else {
operationFieldsPositions = null;
}
if (passThrough != null) {
inputPassThorughPositions = getInputFields().getPos(passThrough);
outputPassThorughPositions = getOutputFields().getPos(passThrough);
} else {
inputPassThorughPositions = null;
outputPassThorughPositions = null;
}
if (mapSourceFields != null) {
mapSourceFieldPositions = getInputFields().getPos(mapSourceFields);
} else {
mapSourceFieldPositions = null;
}
if (mapTargetFields != null) {
mapTargetFieldPositions = getOutputFields().getPos(mapTargetFields);
} else {
mapTargetFieldPositions = null;
}
outputPositions = new ArrayList<int[]>();
if (operationOutputFields != null) {
for (Fields fields : operationOutputFields) {
int [] position = new int[fields.size()];
for (int j = 0; j < fields.size(); j++) {
if(getOutputFields().contains(new Fields(fields.get(j)))){
position[j] = (getOutputFields().getPos(fields.get(j))) ;
}else{
position[j] = -1;
}
}
outputPositions.add(position);
//outputPositions.add(getOperationFields().getPos(fields))
}
}
}
public Fields getKeyFields() {
return keyFields;
}
public Fields getPassThroughFields() {
return passThrough;
}
public Fields getOutputFields() {
return outputFields;
}
public Fields getInputFields() {
return inputFields;
}
public Fields getOutputOperationFields() {
return outputOperationFields;
}
public int[] getInputPositions(int index) {
return inputPositions.get(index);
}
public ArrayList<int[]> getAllInputPositions(){
return inputPositions;
}
/**
* @return the field positions of pass through fields in the input row
*/
public int[] getInputPassThroughPositions() {
// Exposing internal arrays directly allows the user to modify some code
// that could be critical. It is safer to return a copy of the array
return inputPassThorughPositions == null ? null : inputPassThorughPositions
.clone();
}
public int[] getOutputPassThroughPositions() {
// Exposing internal arrays directly allows the user to modify some code
// that could be critical. It is safer to return a copy of the array
return outputPassThorughPositions == null ? null : outputPassThorughPositions
.clone();
}
/**
* @return the field positions of pass through fields in the input row
*/
public int[] getOperationPositions() {
return operationFieldsPositions != null ? operationFieldsPositions.clone() : null;
}
public int[] getInputPositions() {
return getInputPositions(0);
}
public int[] getOutputPositions(int index) {
return outputPositions.get(index);
}
public ArrayList<int[]> getAllOutputPositions() {
return outputPositions;
}
public void setAllOutputPositions(ArrayList<int[]> outputPositions) {
this.outputPositions = outputPositions;
}
/**
* @return the field positions of operation input fields in the input row
*/
public ArrayList<Fields> getOperationInputFields() {
return operationInputFields;
}
/**
* @return the field positions of operation output fields in the input row
*/
public ArrayList<Fields> getOperationOutputFields() {
return operationOutputFields;
}
/**
* @return the field positions of source fields in map fields in the input
* row
*/
public int[] getMapSourceFieldPositions() {
return mapSourceFieldPositions != null ? mapSourceFieldPositions.clone() : null;
}
public int[] getMapTargetFieldPositions() {
return mapTargetFieldPositions != null ? mapTargetFieldPositions.clone() : null;
}
/**
* @return the a map object {@link Map}<{@link String}, {@link String}>
* containing all the map field names. The map fields are stored as
* Map<SourceFieldName, TargetFieldName>
*/
public Map<String, String> getMapFields() {
return mapFields;
}
/**
* @param mapFields
* the mapFields to set. The map fields are stored as
* Map<SourceFieldName, TargetFieldName>
*/
public void setMapFields(Map<String, String> mapFields) {
this.mapFields = mapFields;
}
/**
* @return the source fields for map fields
*/
public Fields getMapSourceFields() {
return mapSourceFields;
}
/**
* @param mapSourceFields
* the mapSourceFields to set
*/
public void setMapSourceFields(Fields mapSourceFields) {
this.mapSourceFields = mapSourceFields;
}
/**
* @return a list of map source fields
*/
public List<String> getMapSourceFieldsAsList() {
if (mapSourceFields == null) {
return null;
}
ArrayList<String> mapSourceFieldsList = new ArrayList<String>();
for (int i = 0; i < mapSourceFields.size(); i++) {
mapSourceFieldsList.add(mapSourceFields.get(i).toString());
}
return mapSourceFieldsList;
}
/**
* @return the target fields for map fields
*/
public Fields getMapTargetFields() {
return mapTargetFields;
}
/**
* @param mapTargetFields
* the mapTargetFields to set
*/
public void setMapTargetFields(Fields mapTargetFields) {
this.mapTargetFields = mapTargetFields;
}
}