io.atlasmap.core.BaseAtlasModule Maven / Gradle / Ivy
/**
* Copyright (C) 2017 Red Hat, 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 io.atlasmap.core;
import java.util.HashMap;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.atlasmap.api.AtlasConversionService;
import io.atlasmap.api.AtlasException;
import io.atlasmap.api.AtlasFieldActionService;
import io.atlasmap.api.AtlasSession;
import io.atlasmap.spi.AtlasModule;
import io.atlasmap.spi.AtlasModuleMode;
import io.atlasmap.spi.AtlasPropertyStrategy;
import io.atlasmap.v2.AtlasModelFactory;
import io.atlasmap.v2.Audit;
import io.atlasmap.v2.AuditStatus;
import io.atlasmap.v2.BaseMapping;
import io.atlasmap.v2.Collection;
import io.atlasmap.v2.ConstantField;
import io.atlasmap.v2.Field;
import io.atlasmap.v2.FieldType;
import io.atlasmap.v2.LookupEntry;
import io.atlasmap.v2.LookupTable;
import io.atlasmap.v2.Mapping;
import io.atlasmap.v2.MappingType;
import io.atlasmap.v2.PropertyField;
import io.atlasmap.v2.SimpleField;
public abstract class BaseAtlasModule implements AtlasModule {
private static final Logger logger = LoggerFactory.getLogger(BaseAtlasModule.class);
private AtlasConversionService atlasConversionService = null;
private AtlasModuleMode atlasModuleMode = AtlasModuleMode.UNSET;
protected boolean automaticallyProcessOutputFieldActions = true;
@Override
public void init() {
}
@Override
public void destroy() {
}
@Override
public void processInputActions(AtlasSession atlasSession, BaseMapping baseMapping) throws AtlasException {
if (baseMapping.getMappingType().equals(MappingType.COLLECTION)) {
return;
}
AtlasFieldActionService fieldActionService = atlasSession.getAtlasContext().getContextFactory()
.getFieldActionService();
Mapping mapping = (Mapping) baseMapping;
for (Field field : mapping.getInputField()) {
processFieldActions(fieldActionService, field);
}
}
@Override
public void processOutputActions(AtlasSession atlasSession, BaseMapping baseMapping) throws AtlasException {
if (!automaticallyProcessOutputFieldActions) {
return;
}
if (baseMapping.getMappingType().equals(MappingType.COLLECTION)) {
return;
}
AtlasFieldActionService fieldActionService = atlasSession.getAtlasContext().getContextFactory()
.getFieldActionService();
Mapping mapping = (Mapping) baseMapping;
for (Field field : mapping.getOutputField()) {
processFieldActions(fieldActionService, field);
}
}
public abstract int getCollectionSize(AtlasSession session, Field field) throws AtlasException;
public abstract Field cloneField(Field field) throws AtlasException;
public List generateInputMappings(AtlasSession session, BaseMapping baseMapping) throws AtlasException {
if (logger.isDebugEnabled()) {
logger.debug("Generating Input Mappings from mapping: " + baseMapping);
}
if (!baseMapping.getMappingType().equals(MappingType.COLLECTION)) {
if (logger.isDebugEnabled()) {
logger.debug("Mapping is not a collection mapping, not cloning: " + baseMapping);
}
return Arrays.asList((Mapping) baseMapping);
}
List mappings = new LinkedList<>();
for (BaseMapping m : ((Collection) baseMapping).getMappings().getMapping()) {
Mapping mapping = (Mapping) m;
Field inputField = mapping.getInputField().get(0);
boolean inputIsCollection = PathUtil.isCollection(inputField.getPath());
if (!inputIsCollection) {
// this is a input non-collection to output collection, ie: contact.firstName ->
// contact[].firstName
// this will be expanded later by generateOutputMappings, for input processing,
// just copy it over
if (logger.isDebugEnabled()) {
logger.debug("Internal mapping's input field is not a collection, not cloning: " + mapping);
}
// this is a output collection such as contact<>.firstName, but input is non
// collection such as contact.firstName
// so just set the output collection field path to be contact<0>.firstName,
// which will cause at least one
// output object to be created for our copied firstName value
for (Field f : mapping.getOutputField()) {
f.setPath(PathUtil.overwriteCollectionIndex(f.getPath(), 0));
}
mappings.add(mapping);
continue;
}
int inputCollectionSize = this.getCollectionSize(session, inputField);
if (logger.isDebugEnabled()) {
logger.debug("Internal mapping's input field is a collection. Cloning it for each item ("
+ inputCollectionSize + " clones): " + mapping);
}
for (int i = 0; i < inputCollectionSize; i++) {
Mapping cloneMapping = (Mapping) AtlasModelFactory.cloneMapping(mapping, false);
for (Field f : mapping.getInputField()) {
Field clonedField = cloneField(f);
clonedField.setPath(PathUtil.overwriteCollectionIndex(clonedField.getPath(), i));
cloneMapping.getInputField().add(clonedField);
}
for (Field f : mapping.getOutputField()) {
Field clonedField = cloneField(f);
if (PathUtil.isCollection(clonedField.getPath())) {
clonedField.setPath(PathUtil.overwriteCollectionIndex(clonedField.getPath(), i));
}
cloneMapping.getOutputField().add(clonedField);
}
mappings.add(cloneMapping);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Generated " + mappings.size() + " mappings from mapping: " + baseMapping);
}
((Collection) baseMapping).getMappings().getMapping().clear();
((Collection) baseMapping).getMappings().getMapping().addAll(mappings);
return mappings;
}
public List getOutputMappings(AtlasSession session, BaseMapping baseMapping) throws AtlasException {
if (!baseMapping.getMappingType().equals(MappingType.COLLECTION)) {
return Arrays.asList((Mapping) baseMapping);
}
List mappings = new LinkedList<>();
for (BaseMapping m : ((Collection) baseMapping).getMappings().getMapping()) {
mappings.add((Mapping) m);
}
return mappings;
}
@Override
public void processPreInputExecution(AtlasSession session) throws AtlasException {
if (logger.isDebugEnabled()) {
logger.debug("processPreInputExcution completed");
}
}
@Override
public void processPostInputExecution(AtlasSession session) throws AtlasException {
if (logger.isDebugEnabled()) {
logger.debug("processPostInputExecution completed");
}
}
@Override
public void processPostValidation(AtlasSession session) throws AtlasException {
if (logger.isDebugEnabled()) {
logger.debug("processPostValidation completed");
}
}
protected void processConstantField(AtlasSession atlasSession, Mapping mapping) throws AtlasException {
for (Field f : mapping.getInputField()) {
if (f instanceof ConstantField) {
if (f.getFieldType() == null && f.getValue() != null) {
f.setFieldType(getConversionService().fieldTypeFromClass(f.getValue().getClass()));
}
}
}
}
protected void processPropertyField(AtlasSession atlasSession, Mapping mapping,
AtlasPropertyStrategy atlasPropertyStrategy) throws AtlasException {
for (Field f : mapping.getInputField()) {
if (f instanceof PropertyField) {
atlasPropertyStrategy.processPropertyField(atlasSession.getMapping(), (PropertyField) f,
atlasSession.getProperties());
}
}
for (Field f : mapping.getOutputField()) {
if (f instanceof PropertyField) {
atlasPropertyStrategy.processPropertyField(atlasSession.getMapping(), (PropertyField) f,
atlasSession.getProperties());
}
}
}
protected void processLookupField(AtlasSession session, Mapping mapping) throws AtlasException {
if (mapping == null || mapping.getMappingType() == null || MappingType.LOOKUP.equals(mapping.getMappingType())
|| mapping.getLookupTableName() == null || mapping.getLookupTableName().trim().length() == 0) {
throw new AtlasException("Lookup mapping must have lookupTableName specified");
}
if (session == null || session.getMapping() == null) {
throw new AtlasException("AtlasSession must be initialized");
}
if (session.getMapping().getLookupTables() == null
|| session.getMapping().getLookupTables().getLookupTable() == null
|| session.getMapping().getLookupTables().getLookupTable().size() == 0) {
logger.warn(String.format("No lookup table found for specified lookupTableName=%s",
mapping.getLookupTableName()));
return;
}
LookupTable currentTable = null;
for (LookupTable lookupTable : session.getMapping().getLookupTables().getLookupTable()) {
if (lookupTable.getName() != null && lookupTable.getName().equals(mapping.getLookupTableName())) {
currentTable = lookupTable;
}
}
if (currentTable.getLookupEntry() == null || currentTable.getLookupEntry().isEmpty()) {
logger.warn(String.format("Lookup table lookupTableName=%s does not contain any entries",
mapping.getLookupTableName()));
return;
}
for (LookupEntry entry : currentTable.getLookupEntry()) {
for (Field inputField : mapping.getInputField()) {
if (entry.getSourceValue().equals(inputField.getValue())) {
inputField.setValue(entry.getTargetValue());
if (logger.isDebugEnabled()) {
logger.debug(
String.format("Processing lookup value for iP=%s iV=%s lksV=%s lksT=%s lktV=%s lktT=%s",
inputField.getPath(), inputField.getValue(), entry.getSourceValue(),
entry.getSourceType(), entry.getTargetValue(), entry.getTargetType()));
}
}
}
}
}
protected Field processSeparateField(AtlasSession session, Mapping mapping, Field inputField, Field outputField)
throws AtlasException {
if (outputField.getIndex() == null || outputField.getIndex() < 0) {
logger.warn(String.format("Separate requires Index value to be set on outputField outputField.path=%s",
outputField.getPath()));
addAudit(session, outputField.getDocId(),
String.format("Separate requires Index value to be set on outputField outputField.path=%s",
outputField.getPath()),
outputField.getPath(), AuditStatus.ERROR, null);
return null;
}
Field inputFieldsep = mapping.getInputField().get(0);
if ((inputFieldsep.getFieldType() != null && !FieldType.STRING.equals(inputFieldsep.getFieldType())
|| (inputFieldsep.getValue() == null
|| !inputFieldsep.getValue().getClass().isAssignableFrom(String.class)))) {
logger.warn(String.format("Separate requires String field type for inputField.path=%s",
inputFieldsep.getPath()));
addAudit(session, outputField.getDocId(), String
.format("Separate requires String field type for inputField.path=%s", inputFieldsep.getPath()),
outputField.getPath(), AuditStatus.WARN, null);
return null;
}
String inputValue = (String) inputFieldsep.getValue();
List separatedValues = null;
if (mapping.getDelimiter() != null) {
separatedValues = session.getAtlasContext().getContextFactory().getSeparateStrategy()
.separateValue(inputValue, mapping.getDelimiter());
} else {
separatedValues = session.getAtlasContext().getContextFactory().getSeparateStrategy()
.separateValue(inputValue);
}
if (separatedValues == null || separatedValues.isEmpty()) {
logger.debug(
String.format("Empty string for Separate mapping inputField.path=%s", inputFieldsep.getPath()));
return null;
}
if (separatedValues.size() < outputField.getIndex()) {
logger.error(String.format(
"Separate returned fewer segements count=%s when outputField.path=%s requested index=%s",
separatedValues.size(), outputField.getPath(), outputField.getIndex()));
addAudit(session, outputField.getDocId(),
String.format(
"Separate returned fewer segements count=%s when outputField.path=%s requested index=%s",
separatedValues.size(), outputField.getPath(), outputField.getIndex()),
outputField.getPath(), AuditStatus.ERROR, null);
return null;
}
SimpleField simpleField = AtlasModelFactory.cloneFieldToSimpleField(inputFieldsep);
simpleField.setValue(separatedValues.get(outputField.getIndex()));
return simpleField;
}
protected void processCombineField(AtlasSession session, Mapping mapping, List inputFields,
Field outputField) throws AtlasException {
Map combineValues = null;
for (Field inputField : inputFields) {
if (inputField.getIndex() == null || inputField.getIndex() < 0) {
logger.error(
String.format("Combine requires Index value to be set on all inputFields inputField.path=%s",
inputField.getPath()));
addAudit(session, outputField.getDocId(),
String.format("Combine requires Index value to be set on all inputFields inputField.path=%s",
inputField.getPath()),
outputField.getPath(), AuditStatus.ERROR, null);
return;
}
if ((inputField.getFieldType() != null && !FieldType.STRING.equals(inputField.getFieldType())
|| (inputField.getValue() != null
&& !inputField.getValue().getClass().isAssignableFrom(String.class)))) {
logger.error(String.format("Combine requires String field type for inputField.path=%s",
inputField.getPath()));
addAudit(session, outputField.getDocId(), String
.format("Combine requires String field type for inputField.path=%s", inputField.getPath()),
outputField.getPath(), AuditStatus.WARN, null);
continue;
}
if (combineValues == null) {
// We need to support a sorted map w/ null values
combineValues = new HashMap();
}
combineValues.put(inputField.getIndex(), (String) inputField.getValue());
}
String combinedValue = null;
if (mapping.getDelimiter() != null) {
combinedValue = session.getAtlasContext().getContextFactory().getCombineStrategy()
.combineValues(combineValues, mapping.getDelimiter());
} else {
combinedValue = session.getAtlasContext().getContextFactory().getCombineStrategy()
.combineValues(combineValues);
}
if (combinedValue == null || combinedValue.trim().isEmpty()) {
logger.debug(String.format("Empty combined string for Combine mapping outputField.path=%s",
outputField.getPath()));
return;
}
outputField.setValue(combinedValue);
}
protected void processLookupField(AtlasSession session, String lookupTableName, String inputValue,
Field outputField) throws AtlasException {
LookupTable table = null;
for (LookupTable t : session.getMapping().getLookupTables().getLookupTable()) {
if (t.getName().equals(lookupTableName)) {
table = t;
break;
}
}
if (table == null) {
throw new AtlasException("Could not find lookup table with name '" + lookupTableName + "' for outputField: "
+ outputField.getPath());
}
String lookupValue = null;
FieldType lookupType = null;
for (LookupEntry lkp : table.getLookupEntry()) {
if (lkp.getSourceValue().equals(inputValue)) {
lookupValue = lkp.getTargetValue();
lookupType = lkp.getTargetType();
break;
}
}
Object outputValue = null;
if (lookupType == null || FieldType.STRING.equals(lookupType)) {
outputValue = lookupValue;
} else {
outputValue = getConversionService().convertType(lookupValue, FieldType.STRING, lookupType);
}
if (outputField.getFieldType() != null && !outputField.getFieldType().equals(lookupType)) {
outputValue = getConversionService().convertType(outputValue, lookupType, outputField.getFieldType());
}
outputField.setValue(outputValue);
}
protected void addAudit(AtlasSession session, String docId, String message, String path, AuditStatus status,
String value) {
Audit audit = new Audit();
audit.setDocId(docId);
audit.setMessage(message);
audit.setPath(path);
audit.setStatus(status);
audit.setValue(value);
session.getAudits().getAudit().add(audit);
}
protected void processFieldActions(AtlasFieldActionService fieldActionService, Field field) throws AtlasException {
field.setValue(fieldActionService.processActions(field.getActions(), field.getValue(), field.getFieldType()));
}
@Override
public AtlasModuleMode getMode() {
return this.atlasModuleMode;
}
@Override
public void setMode(AtlasModuleMode atlasModuleMode) {
this.atlasModuleMode = atlasModuleMode;
}
@Override
public Boolean isStatisticsSupported() {
return false;
}
@Override
public Boolean isStatisticsEnabled() {
return false;
}
@Override
public List listSupportedModes() {
return Arrays.asList(AtlasModuleMode.SOURCE, AtlasModuleMode.TARGET);
}
@Override
public AtlasConversionService getConversionService() {
return atlasConversionService;
}
@Override
public void setConversionService(AtlasConversionService atlasConversionService) {
this.atlasConversionService = atlasConversionService;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy