/******************************************************************************* * 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.utils; import cascading.tuple.Fields; import hydrograph.engine.cascading.assembly.infra.ComponentParameters; import hydrograph.engine.core.component.entity.elements.MapField; import hydrograph.engine.core.component.entity.elements.OutSocket; import hydrograph.engine.core.component.entity.elements.PassThroughField; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public class JoinHelper { ComponentParameters componentParameters = new ComponentParameters(); public JoinHelper(ComponentParameters params) { super(); this.componentParameters = params; } Map<String, Map<Fields, Fields>> fileMap; @SuppressWarnings("rawtypes") public Fields getMapTargetFields(OutSocket outSocket) { Set<Fields> rawTargetFields = getRawTargetFields(outSocket); Fields targetFields = new Fields(); fileMap = getFieldsMap(outSocket); if (fileMap == null) { return null; } int i = 0; for (Entry<String, Map<Fields, Fields>> fieldsMapEntry : fileMap .entrySet()) { Map<Fields, Fields> fieldsMap = fieldsMapEntry.getValue(); String socketId = fieldsMapEntry.getKey(); Fields inputFields = null; for (int j = 0; j < componentParameters.getinSocketId().size(); j++) { if (socketId .equalsIgnoreCase(componentParameters.getinSocketId().get(j))) { inputFields = componentParameters.getInputFieldsList().get(j); } } for (Entry<Fields, Fields> e : fieldsMap.entrySet()) { Fields fields = e.getKey(); String field = fields.get(0).toString(); // get one to one field mapping if (!field.equals("*") && !field.endsWith(".*")) if (targetFields.contains(fields)) { targetFields = targetFields.append(fields.rename( fields, new Fields("in" + i + "." + fields))); } else { targetFields = targetFields.append(fields); } // get wildcard field mapping if (field.endsWith(".*") || field.equals("*")) { String targetPrefix = field.replaceAll("\\*$", ""); String sourcePrefix = e.getValue().get(0).toString() .replaceAll("\\*$", ""); for (Comparable inputFieldName : inputFields) { if (inputFieldName.toString().startsWith(sourcePrefix)) { String fieldName = inputFieldName.toString() .replaceAll("^" + sourcePrefix, targetPrefix); if (!rawTargetFields .contains(new Fields(fieldName)) && !fieldsMap.values().contains( new Fields(inputFieldName))) { targetFields = targetFields.append(new Fields( fieldName)); } } } } } i++; } return targetFields; } private Map<String, Map<Fields, Fields>> getFieldsMap(OutSocket outSocket) { Map<String, Map<Fields, Fields>> fieldAndInSocketIdMap = new LinkedHashMap<String, Map<Fields, Fields>>(); Map<Fields, Fields> fieldsMaps = null; for (String socketID : componentParameters.getinSocketId()) { // Check if outSocket contains copyOfInSocketId if (outSocket.getMapFieldsList().size() == 0 && outSocket.getPassThroughFieldsList().size() == 0 && outSocket.getCopyOfInSocketId() != null) { if (fieldAndInSocketIdMap.get(socketID) == null) { fieldsMaps = new LinkedHashMap<Fields, Fields>(); } if (socketID .equals(outSocket.getCopyOfInSocketId())) { Fields copyFieldsOfInSocketId = componentParameters .getCopyOfInSocket(socketID); for (int i = 0; i < copyFieldsOfInSocketId.size(); i++) { fieldsMaps.put( new Fields(copyFieldsOfInSocketId.get(i)), new Fields(copyFieldsOfInSocketId.get(i))); fieldAndInSocketIdMap.put(socketID, fieldsMaps); } } } else { // Populate map for mapFields and passThroughFields for (MapField mapField : outSocket.getMapFieldsList()) { if (fieldAndInSocketIdMap.get(mapField.getInSocketId()) == null) { fieldsMaps = new LinkedHashMap<Fields, Fields>(); } if (mapField.getInSocketId().equalsIgnoreCase(socketID)) { fieldsMaps.put(new Fields(mapField.getName()), new Fields(mapField.getSourceName())); fieldAndInSocketIdMap.put(mapField.getInSocketId(), fieldsMaps); } } for (PassThroughField passThroughField : outSocket .getPassThroughFieldsList()) { if (passThroughField.getInSocketId().equalsIgnoreCase( socketID)) { if (fieldAndInSocketIdMap.get(passThroughField.getInSocketId()) == null) { fieldsMaps = new LinkedHashMap<Fields, Fields>(); } else { fieldsMaps = fieldAndInSocketIdMap.get(passThroughField .getInSocketId()); } fieldsMaps.put(new Fields(passThroughField.getName()), new Fields(passThroughField.getName())); fieldAndInSocketIdMap.put(passThroughField.getInSocketId(), fieldsMaps); } } } } // } return fieldAndInSocketIdMap; } @SuppressWarnings("rawtypes") public Fields getMapSourceFields(String inSocketId, OutSocket outSocket) { Fields sourceFields = new Fields(); Map<Fields, Fields> fieldMap = getMapFields(outSocket, inSocketId); Set<Fields> rawTargetFields = getRawTargetFields(outSocket); Set<Fields> rawSourceFields = getRawSourceFields(fieldMap); Fields inputFields = componentParameters.getCopyOfInSocket(inSocketId); if (fieldMap == null) { return null; } for (Fields fields : fieldMap.keySet()) { String field = fields.get(0).toString(); // get one to one field mapping if (!field.equals("*") && !field.endsWith(".*")) sourceFields = sourceFields.append(fields); // get wildcard field mapping if (field.endsWith(".*") || field.equals("*")) { String prefix = field.replaceAll("\\*$", ""); String targetPrefix = ""; targetPrefix = getKeyFromValue(fieldMap, field); targetPrefix = targetPrefix.replace("*", ""); for (Comparable inputFieldName : inputFields) { if (inputFieldName.toString().startsWith(prefix)) { if (!rawSourceFields .contains(new Fields(inputFieldName)) && !rawTargetFields.contains(new Fields( targetPrefix + inputFieldName))) { sourceFields = sourceFields.append(new Fields( inputFieldName)); } } } } } return sourceFields; } public static String getKeyFromValue(Map<Fields, Fields> fieldsMap, String value) { for (Entry<Fields, Fields> e : fieldsMap.entrySet()) { if (e.getKey().get(0).equals(value)) { return (String) e.getValue().get(0); } } return null; } private Set<Fields> getRawSourceFields(Map<Fields, Fields> fieldMap) { Set<Fields> rawSourceFields = new LinkedHashSet<Fields>(); if (fieldMap == null) { return null; } rawSourceFields.addAll(fieldMap.keySet()); return rawSourceFields; } private Set<Fields> getRawTargetFields(OutSocket outSocket) { Set<Fields> rawTargetFields = new LinkedHashSet<Fields>(); for (PassThroughField passthroughFields : outSocket .getPassThroughFieldsList()) { rawTargetFields.add(new Fields(passthroughFields.getName())); } return rawTargetFields; } private Map<Fields, Fields> getMapFields(OutSocket outSocket, String inSocketId) { Map<Fields, Fields> fieldMap = new LinkedHashMap<Fields, Fields>(); // Check if outSocket contains copyOfInSocketId if (outSocket.getMapFieldsList().size() == 0 && outSocket.getPassThroughFieldsList().size() == 0 && outSocket.getCopyOfInSocketId() != null) { if (outSocket.getCopyOfInSocketId().equals(inSocketId)){ Fields copyFieldsOfInSocketId = componentParameters .getCopyOfInSocket(inSocketId); for (int i = 0; i < copyFieldsOfInSocketId.size(); i++) { fieldMap.put(new Fields(copyFieldsOfInSocketId.get(i)), new Fields(copyFieldsOfInSocketId.get(i))); } } } else { // Populate map for mapFields and passThroughFields for (MapField mapField : outSocket.getMapFieldsList()) { if (mapField.getInSocketId().equalsIgnoreCase(inSocketId)) { fieldMap.put(new Fields(mapField.getSourceName()), new Fields(mapField.getName())); } } for (PassThroughField passthroughFields : outSocket .getPassThroughFieldsList()) { if (passthroughFields.getInSocketId().equalsIgnoreCase( inSocketId)) { if (fieldMap.containsKey(new Fields(passthroughFields .getName()))) { throw new RuntimeException( "Pass Through Fields:'" + passthroughFields.getName() + "' is already defined as Map Field in Out Socket '" + outSocket.getSocketId() + "' of join component"); } else { fieldMap.put(new Fields(passthroughFields.getName()), new Fields(passthroughFields.getName())); } } } } return fieldMap; } }