use of io.atlasmap.spi.ActionProcessor in project atlasmap by atlasmap.
the class DefaultAtlasFieldActionsServiceTest method testProcessActionWithActionActionDetailObjectAssignableType.
@Test
public void testProcessActionWithActionActionDetailObjectAssignableType() throws AtlasException {
Action action = new AbsoluteValue();
Object sourceObject = Integer.valueOf("1");
ActionProcessor processor = fieldActionsService.findActionProcessor(action, FieldType.STRING);
assertEquals(1L, processor.process(action, sourceObject));
}
use of io.atlasmap.spi.ActionProcessor in project atlasmap by atlasmap.
the class DefaultAtlasFunctionResolver method resolve.
@Override
public Expression resolve(final String name, List<Expression> args) throws ParseException {
String functionName = name.toUpperCase();
FunctionFactory f = functions.get(functionName);
if (f != null) {
return f.create(args);
} else {
// lookup action
return (ctx) -> {
List<Field> arguments = new ArrayList<>();
for (Expression arg : args) {
arguments.add(arg.evaluate(ctx));
}
Object valueForTypeEvaluation = null;
if (arguments.isEmpty()) {
return null;
} else {
valueForTypeEvaluation = arguments.get(arguments.size() - 1);
}
ActionProcessor actionProcessor = fieldActionService.findActionProcessor(name, valueForTypeEvaluation);
if (actionProcessor != null) {
Map<String, Object> actionParameters = new HashMap<>();
ActionParameters actionDetailParameters = actionProcessor.getActionDetail().getParameters();
if (actionDetailParameters != null && actionDetailParameters.getParameter() != null) {
for (ActionParameter parameter : actionDetailParameters.getParameter()) {
if (!arguments.isEmpty()) {
Object parameterValue = arguments.remove(0).getValue();
actionParameters.put(parameter.getName(), parameterValue);
} else {
throw new IllegalArgumentException(String.format("The transformation '%s' expects more parameters. The parameter '%s' is missing", name, parameter.getName()));
}
}
}
if (arguments.isEmpty()) {
throw new IllegalArgumentException(String.format("The transformation '%s' expects more arguments", name));
}
FieldGroup fields = new FieldGroup();
fields.getField().addAll(arguments);
return fieldActionService.buildAndProcessAction(actionProcessor, actionParameters, fields);
} else {
throw new IllegalArgumentException(String.format("The expression function or transformation '%s' was not found", name));
}
};
}
}
use of io.atlasmap.spi.ActionProcessor in project atlasmap by atlasmap.
the class DefaultAtlasFieldActionService method createDetailFromProcessor.
private ActionProcessor createDetailFromProcessor(Class<?> clazz, Method method) {
AtlasActionProcessor annotation = method.getAnnotation(AtlasActionProcessor.class);
if (annotation == null) {
return null;
}
if (method.getParameterCount() < 1) {
LOG.debug("Invalid @AtlasActionProcessor method. Expected at least 1 parameter: " + method);
}
Class<? extends Action> actionClazz = null;
if (Action.class.isAssignableFrom(method.getParameterTypes()[0])) {
actionClazz = (Class<? extends Action>) method.getParameterTypes()[0];
} else {
LOG.debug("Invalid @AtlasActionProcessor method. 1st parameter does not subclass " + Action.class.getName() + ": " + method);
}
final Class<?> targetClass = method.getReturnType();
String name = actionResolver.toId(actionClazz);
ActionDetail det = new ActionDetail();
det.setClassName(clazz.getName());
det.setMethod(method.getName());
det.setName(name);
det.setTargetType(toFieldType(targetClass, method.getGenericReturnType()));
if (!clazz.getPackage().getName().equals("io.atlasmap.actions")) {
det.setCustom(true);
}
Type[] genericParameterTypes = method.getGenericParameterTypes();
if (genericParameterTypes.length >= 2) {
Class<?> sourceClass = method.getParameterTypes()[1];
if (annotation.sourceType() != FieldType.NONE) {
det.setSourceType(annotation.sourceType());
} else {
det.setSourceType(toFieldType(sourceClass, method.getGenericParameterTypes()[1]));
}
CollectionType sourceCollection = toFieldCollectionType(sourceClass);
CollectionType targetCollection = toFieldCollectionType(targetClass);
if (sourceCollection != CollectionType.NONE) {
if (targetCollection != CollectionType.NONE) {
det.setMultiplicity(Multiplicity.MANY_TO_MANY);
} else {
det.setMultiplicity(Multiplicity.MANY_TO_ONE);
}
} else if (targetCollection != CollectionType.NONE) {
det.setMultiplicity(Multiplicity.ONE_TO_MANY);
} else {
det.setMultiplicity(Multiplicity.ONE_TO_ONE);
}
} else if (genericParameterTypes.length == 1) {
det.setMultiplicity(Multiplicity.ZERO_TO_ONE);
}
try {
det.setActionSchema(actionClazz);
} catch (Exception e) {
LOG.error(String.format("Could not get json schema for action=%s msg=%s", clazz.getName(), e.getMessage()), e);
}
try {
det.setParameters(detectFieldActionParameters(actionClazz));
} catch (ClassNotFoundException e) {
LOG.error(String.format("Error detecting parameters for field action=%s msg=%s", det.getName(), e.getMessage()), e);
}
Object o = null;
try {
o = Modifier.isStatic(method.getModifiers()) ? clazz.getDeclaredConstructor().newInstance() : null;
} catch (Throwable e) {
LOG.error(String.format("Error creating object instance for action=%s msg=%s", det.getName(), e.getMessage()), e);
}
final Object object = o;
Class<? extends Action> finalActionClazz = actionClazz;
return new ActionProcessor() {
@Override
public ActionDetail getActionDetail() {
return det;
}
@Override
public Class<? extends Action> getActionClass() {
return finalActionClazz;
}
@Override
public Object process(Action action, Object sourceObject) throws AtlasException {
try {
if (det.getMultiplicity() == Multiplicity.ZERO_TO_ONE) {
return method.invoke(object, action);
} else {
sourceObject = convertSourceObject(sourceObject);
return method.invoke(object, action, sourceObject);
}
} catch (Throwable e) {
throw new AtlasException(String.format("Error processing action %s", det.getName()), e);
}
}
private Object convertSourceObject(Object sourceObject) throws AtlasConversionException {
if (sourceObject == null) {
return null;
}
Class<?> paramType;
paramType = method.getParameterTypes()[1];
CollectionType paramCollectionType = toFieldCollectionType(paramType);
CollectionType sourceCollectionType = toFieldCollectionType(sourceObject.getClass());
if (paramCollectionType != CollectionType.NONE) {
List<Object> sourceList;
Type itemType = method.getGenericParameterTypes()[1];
Class<?> itemClass = paramType.isArray() ? paramType.getComponentType() : (Class<?>) ((ParameterizedType) itemType).getActualTypeArguments()[0];
if (sourceCollectionType != CollectionType.NONE) {
if (sourceCollectionType == CollectionType.ARRAY) {
sourceList = Arrays.asList(sourceObject);
} else if (sourceCollectionType == CollectionType.LIST) {
sourceList = (List<Object>) sourceObject;
} else if (sourceCollectionType == CollectionType.MAP) {
sourceList = new ArrayList(((Map) sourceObject).values());
} else {
sourceList = new ArrayList((Collection) sourceObject);
}
} else {
sourceList = Arrays.asList(sourceObject);
}
convertItems(sourceList, itemClass);
if (paramType.isArray()) {
return sourceList.toArray();
} else {
return sourceList;
}
} else if (paramType.isInstance(sourceObject)) {
return sourceObject;
}
return conversionService.convertType(sourceObject, null, paramType, null);
}
};
}
use of io.atlasmap.spi.ActionProcessor in project atlasmap by atlasmap.
the class DefaultAtlasFieldActionService method createDetailFromFieldActionInfo.
private ActionProcessor createDetailFromFieldActionInfo(final Class<?> clazz, final Method method) {
AtlasFieldActionInfo annotation = method.getAnnotation(AtlasFieldActionInfo.class);
if (annotation == null) {
return null;
}
final ActionDetail det = new ActionDetail();
det.setClassName(clazz.getName());
det.setMethod(method.getName());
det.setName(annotation.name());
det.setSourceType(annotation.sourceType());
det.setTargetType(annotation.targetType());
CollectionType sourceCollection = annotation.sourceCollectionType();
CollectionType targetCollection = annotation.sourceCollectionType();
if (sourceCollection != null && sourceCollection != CollectionType.NONE) {
det.setMultiplicity(Multiplicity.MANY_TO_ONE);
} else if (targetCollection != null && targetCollection != CollectionType.NONE) {
det.setMultiplicity(Multiplicity.ONE_TO_MANY);
} else {
det.setMultiplicity(Multiplicity.ONE_TO_ONE);
}
Class<? extends Action> actionClazz;
try {
actionClazz = (Class<? extends Action>) Class.forName("io.atlasmap.v2." + annotation.name());
} catch (Exception e) {
actionClazz = null;
det.setCustom(true);
}
try {
det.setActionSchema(actionClazz);
} catch (Exception e) {
LOG.error(String.format("Could not get json schema for action=%s msg=%s", annotation.name(), e.getMessage()), e);
}
try {
// TODO https://github.com/atlasmap/atlasmap/issues/538
if (det.isCustom() == null || !det.isCustom()) {
det.setParameters(detectFieldActionParameters(actionClazz));
}
} catch (ClassNotFoundException e) {
LOG.error(String.format("Error detecting parameters for field action=%s msg=%s", annotation.name(), e.getMessage()), e);
}
if (LOG.isTraceEnabled()) {
LOG.trace("Loaded FieldAction: " + det.getName());
}
Class<? extends Action> finalActionClazz = actionClazz;
return new ActionProcessor() {
@Override
public ActionDetail getActionDetail() {
return det;
}
@Override
public Class<? extends Action> getActionClass() {
return finalActionClazz;
}
@Override
public Object process(Action action, Object sourceObject) throws AtlasException {
Object targetObject = null;
try {
Object convertedSourceObject = convertSourceObject(sourceObject);
if (Modifier.isStatic(method.getModifiers())) {
// cf. https://github.com/atlasmap/atlasmap/issues/536
if (det.isCustom() != null && det.isCustom()) {
targetObject = det.getMultiplicity() == Multiplicity.ZERO_TO_ONE ? method.invoke(null) : method.invoke(null, convertedSourceObject);
} else {
targetObject = det.getMultiplicity() == Multiplicity.ZERO_TO_ONE ? method.invoke(null, action) : method.invoke(null, action, convertedSourceObject);
}
} else {
Object object = clazz.getDeclaredConstructor().newInstance();
if (det.isCustom() != null && det.isCustom()) {
targetObject = det.getMultiplicity() == Multiplicity.ZERO_TO_ONE ? method.invoke(object) : method.invoke(object, convertedSourceObject);
} else {
targetObject = det.getMultiplicity() == Multiplicity.ZERO_TO_ONE ? method.invoke(object, action) : method.invoke(object, action, convertedSourceObject);
}
}
} catch (Throwable e) {
throw new AtlasException(String.format("Error processing action %s", det.getName()), e);
}
return targetObject;
}
private Object convertSourceObject(Object sourceObject) throws AtlasConversionException {
Class<?> paramType;
int paramCount = method.getParameterCount();
if (paramCount < 2) {
return null;
}
paramType = method.getParameterTypes()[1];
if (paramType.isInstance(sourceObject)) {
return sourceObject;
}
return conversionService.convertType(sourceObject, null, paramType, null);
}
};
}
use of io.atlasmap.spi.ActionProcessor in project atlasmap by atlasmap.
the class DefaultAtlasFieldActionService method findActionProcessor.
@Override
public ActionProcessor findActionProcessor(Action action, FieldType sourceType) throws AtlasException {
CustomAction customAction = null;
if (action instanceof CustomAction) {
customAction = (CustomAction) action;
if (customAction.getClassName() == null || customAction.getMethodName() == null) {
throw new AtlasException("The class name and method name must be specified for custom FieldAction: " + customAction.getName());
}
}
List<ActionProcessor> matches = new ArrayList<>();
Lock readLock = actionProcessorsLock.readLock();
try {
readLock.lock();
for (ActionProcessor processor : actionProcessors) {
if (customAction != null) {
ActionDetail detail = processor.getActionDetail();
if (customAction.getClassName().equals(detail.getClassName()) && customAction.getMethodName().equals(detail.getMethod())) {
matches.add(processor);
break;
}
} else if (processor.getActionClass() == action.getClass()) {
matches.add(processor);
}
}
} finally {
readLock.unlock();
}
return findBestActionProcessor(matches, sourceType);
}
Aggregations