/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.core.el.mvel.datatype; import org.mule.mvel2.ast.ASTNode; import org.mule.mvel2.ast.AssignmentNode; import org.mule.mvel2.ast.DeepAssignmentNode; import org.mule.mvel2.compiler.AccessorNode; import org.mule.mvel2.compiler.CompiledAccExpression; import org.mule.mvel2.compiler.ExecutableLiteral; import org.mule.mvel2.optimizers.impl.refl.nodes.MapAccessor; import org.mule.mvel2.optimizers.impl.refl.nodes.MapAccessorNest; import org.mule.mvel2.optimizers.impl.refl.nodes.VariableAccessor; import org.mule.runtime.api.metadata.TypedValue; import org.mule.runtime.core.api.Event; import java.lang.reflect.Field; /** * Base class {@link EnricherDataTypePropagator} that propagate data type to message properties. */ public abstract class AbstractVariableEnricherDataTypePropagator extends AbstractEnricherDataTypePropagator { private final String propertyName; private final Field accExprFieldForMapSyntax; private final Field accExprFieldForDotSyntax; public AbstractVariableEnricherDataTypePropagator(String propertyName) { this.propertyName = propertyName; try { // Needs to use reflection to access parsing information not available on the available interfaces accExprFieldForMapSyntax = AssignmentNode.class.getDeclaredField("accExpr"); accExprFieldForMapSyntax.setAccessible(true); accExprFieldForDotSyntax = DeepAssignmentNode.class.getDeclaredField("acc"); accExprFieldForDotSyntax.setAccessible(true); } catch (NoSuchFieldException e) { throw new IllegalStateException(e); } } @Override protected boolean doPropagate(Event event, Event.Builder builder, TypedValue typedValue, ASTNode node) { if (isAssignmentNode(node)) { CompiledAccExpression compiledAccExpression = getCompiledAccExpression(node); if (compiledAccExpression.getAccessor() instanceof VariableAccessor) { VariableAccessor variableAccessor = (VariableAccessor) compiledAccExpression.getAccessor(); if (variableAccessor.getProperty().equals(propertyName)) { final AccessorNode nextNode = variableAccessor.getNextNode(); if (nextNode.getNextNode() == null) { String propertyName = null; if (nextNode instanceof MapAccessorNest) { final MapAccessorNest mapAccesorNest = (MapAccessorNest) nextNode; if (mapAccesorNest.getProperty().isLiteralOnly()) { propertyName = (String) ((ExecutableLiteral) mapAccesorNest.getProperty()).getLiteral(); } } else if (nextNode instanceof MapAccessor) { propertyName = (String) ((MapAccessor) nextNode).getProperty(); } if (propertyName != null && containsVariable(event, propertyName)) { propertyName = getUnescapedPropertyName(propertyName); addVariable(event, builder, typedValue, propertyName); return true; } } } } } return false; } protected abstract void addVariable(Event event, Event.Builder builder, TypedValue typedValue, String propertyName); protected abstract boolean containsVariable(Event event, String propertyName); private String getUnescapedPropertyName(String propertyName) { if (propertyName.startsWith("'") && propertyName.endsWith("'")) { propertyName = propertyName.substring(1, propertyName.length() - 1); } return propertyName; } private boolean isAssignmentNode(ASTNode node) { return node instanceof AssignmentNode && ((AssignmentNode) node).getAssignmentVar().startsWith(propertyName) || node instanceof DeepAssignmentNode && ((DeepAssignmentNode) node).getAssignmentVar().startsWith(propertyName); } private CompiledAccExpression getCompiledAccExpression(ASTNode node) { try { if (node instanceof AssignmentNode) { return (CompiledAccExpression) accExprFieldForMapSyntax.get(node); } else { return (CompiledAccExpression) accExprFieldForDotSyntax.get(node); } } catch (IllegalAccessException e) { throw new IllegalStateException(e); } } }