All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.atlasmap.core.DefaultAtlasFieldActionService Maven / Gradle / Ivy

package io.atlasmap.core;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.util.List;
import java.util.ServiceLoader;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.atlasmap.api.AtlasConversionService;
import io.atlasmap.api.AtlasException;
import io.atlasmap.api.AtlasFieldAction;
import io.atlasmap.api.AtlasFieldActionService;
import io.atlasmap.spi.AtlasFieldActionInfo;
import io.atlasmap.v2.ActionDetails;
import io.atlasmap.v2.Actions;
import io.atlasmap.v2.FieldType;
import io.atlasmap.v2.Properties;
import io.atlasmap.v2.Property;
import io.atlasmap.v2.Action;
import io.atlasmap.v2.ActionDetail;

public class DefaultAtlasFieldActionService implements AtlasFieldActionService {

    private static final Logger logger = LoggerFactory.getLogger(DefaultAtlasFieldActionService.class);
    private ActionDetails actionDetails = new ActionDetails();
    private AtlasConversionService conversionService = null;

    public DefaultAtlasFieldActionService(AtlasConversionService conversionService) {
        this.conversionService = conversionService;
    }

    public void init() {
        loadFieldActions();
    }

    protected void loadFieldActions() {
        ClassLoader classLoader = this.getClass().getClassLoader();
        final ServiceLoader fieldActionServiceLoader = ServiceLoader.load(AtlasFieldAction.class,
                classLoader);
        for (final AtlasFieldAction atlasFieldAction : fieldActionServiceLoader) {
            if (logger.isDebugEnabled()) {
                logger.debug("Loading FieldAction class: " + atlasFieldAction.getClass().getCanonicalName());
            }

            Class clazz = atlasFieldAction.getClass();
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                AtlasFieldActionInfo annotation = method.getAnnotation(AtlasFieldActionInfo.class);
                if (annotation != null) {
                    ActionDetail det = new ActionDetail();
                    det.setClassName(clazz.getName());
                    det.setMethod(method.getName());
                    det.setName(annotation.name());
                    det.setSourceType(annotation.sourceType());
                    det.setTargetType(annotation.targetType());
                    det.setSourceCollectionType(annotation.sourceCollectionType());
                    det.setTargetCollectionType(annotation.targetCollectionType());

                    try {
                        det.setParameters(detectFieldActionParameters("io.atlasmap.v2." + annotation.name()));
                    } catch (ClassNotFoundException e) {
                        logger.error(String.format("Error detecting parameters for field action=%s msg=%s",
                                annotation.name(), e.getMessage()), e);
                    }

                    if (logger.isTraceEnabled()) {
                        logger.trace("Loaded FieldAction: " + det.getName());
                    }
                    listActionDetails().add(det);
                }
            }
        }

        if (logger.isDebugEnabled()) {
            logger.debug(String.format("Loaded %s Field Actions", listActionDetails().size()));
        }
    }

    @Override
    public List listActionDetails() {
        return actionDetails.getActionDetail();
    }

    protected ActionDetail getActionDetailByActionName(String actionName) {
        for (ActionDetail actionDetail : listActionDetails()) {
            if (actionDetail.getName().equals(actionName)) {
                return actionDetail;
            }
        }

        return null;
    }

    @Override
    public Object processActions(Actions actions, Object sourceObject, FieldType targetType) throws AtlasException {

        if (FieldType.COMPLEX.equals(targetType)) {
            return sourceObject;
        }

        Object targetObject = null;
        Object tmpSourceObject = sourceObject;
        FieldType sourceType = (sourceObject != null
                ? getConversionService().fieldTypeFromClass(sourceObject.getClass())
                : FieldType.NONE);

        if (actions == null || actions.getActions() == null || actions.getActions().isEmpty()) {
            if (sourceObject == null) {
                return null;
            }
            return getConversionService().convertType(sourceObject, sourceType, targetType);
        }

        FieldType currentType = sourceType;
        for (Action action : actions.getActions()) {
            ActionDetail detail = getActionDetailByActionName(action.getClass().getSimpleName());
            if (!detail.getSourceType().equals(currentType) && !FieldType.ALL.equals(detail.getSourceType())) {
                tmpSourceObject = getConversionService().convertType(sourceObject, currentType, detail.getSourceType());
            }

            targetObject = processAction(action, getActionDetailByActionName(action.getClass().getSimpleName()),
                    tmpSourceObject);
            currentType = detail.getTargetType();
        }

        if (currentType != null && !currentType.equals(targetType)) {
            targetObject = getConversionService().convertType(targetObject, currentType, targetType);
        }

        return targetObject;
    }

    protected Object processAction(Action action, ActionDetail actionDetail, Object sourceObject)
            throws AtlasException {
        Object targetObject = null;
        if (actionDetail != null) {
            Object actionObject = null;
            try {
                Class actionClazz = Class.forName(actionDetail.getClassName());
                actionObject = actionClazz.newInstance();

                Method method = null;
                if (actionDetail.getSourceType() != null) {
                    switch (actionDetail.getSourceType()) {
                    case BOOLEAN:
                        method = actionClazz.getMethod(actionDetail.getMethod(), Action.class, Boolean.class);
                        break;
                    case BYTE:
                        method = actionClazz.getMethod(actionDetail.getMethod(), Action.class, Byte.class);
                        break;
                    case BYTE_ARRAY:
                        method = actionClazz.getMethod(actionDetail.getMethod(), Action.class, Byte[].class);
                        break;
                    case CHAR:
                        method = actionClazz.getMethod(actionDetail.getMethod(), Action.class, Character.class);
                        break;
                    case DOUBLE:
                        method = actionClazz.getMethod(actionDetail.getMethod(), Action.class, Double.class);
                        break;
                    case FLOAT:
                        method = actionClazz.getMethod(actionDetail.getMethod(), Action.class, Float.class);
                        break;
                    case INTEGER:
                        method = actionClazz.getMethod(actionDetail.getMethod(), Action.class, Integer.class);
                        break;
                    case LONG:
                        method = actionClazz.getMethod(actionDetail.getMethod(), Action.class, Long.class);
                        break;
                    case SHORT:
                        method = actionClazz.getMethod(actionDetail.getMethod(), Action.class, Short.class);
                        break;
                    case STRING:
                        method = actionClazz.getMethod(actionDetail.getMethod(), Action.class, String.class);
                        break;
                    case ALL:
                        method = actionClazz.getMethod(actionDetail.getMethod(), Action.class, Object.class);
                        break;
                    default:
                        logger.warn(String.format("Unsupported sourceType=%s in actionClass=%s",
                                actionDetail.getSourceType().value(), actionDetail.getClassName()));
                        break;
                    }
                }

                if (method == null) {
                    throw new AtlasException(
                            String.format("Unable to locate field action className=%s method=%s sourceType=%s",
                                    actionDetail.getClassName(), actionDetail.getMethod(),
                                    actionDetail.getSourceType().value()));
                }

                if (Modifier.isStatic(method.getModifiers())) {
                    targetObject = method.invoke(null, action, sourceObject);
                } else {
                    targetObject = method.invoke(actionObject, action, sourceObject);
                }
            } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | SecurityException
                    | ClassNotFoundException | IllegalArgumentException | InvocationTargetException e) {
                throw new AtlasException(String.format("Error processing action %s", actionDetail.getName()), e);
            }
            return targetObject;
        }
        return sourceObject;
    }

    protected Properties detectFieldActionParameters(String actionClassName) throws ClassNotFoundException {
        Class actionClazz = Class.forName(actionClassName);

        Properties props = null;
        for (Method method : actionClazz.getMethods()) {
            // Find setters to avoid the get / is confusion
            if (method.getParameterCount() == 1 && method.getName().startsWith("set")) {
                // We have a parameter
                if (props == null) {
                    props = new Properties();
                }

                Property prop = null;
                for (Parameter param : method.getParameters()) {
                    prop = new Property();
                    prop.setName(camelize(method.getName().substring("set".length())));
                    prop.setFieldType(getConversionService().fieldTypeFromClass(param.getType()));
                    props.getProperty().add(prop);
                }
            }
        }

        return props;
    }

    public AtlasConversionService getConversionService() {
        return this.conversionService;
    }

    public static String camelize(String parameter) {
        if (parameter == null || parameter.length() == 0) {
            return parameter;
        }
        char c[] = parameter.toCharArray();
        c[0] = Character.toLowerCase(c[0]);
        return new String(c);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy