// ============================================================================
//
// Copyright (C) 2006-2012 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package org.talend.designer.core.model.components;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.talend.commons.utils.StringUtils;
import org.talend.commons.utils.system.EnvironmentUtils;
import org.talend.core.language.LanguageManager;
import org.talend.core.model.metadata.IMetadataColumn;
import org.talend.core.model.metadata.IMetadataTable;
import org.talend.core.model.metadata.types.JavaTypesManager;
import org.talend.core.model.process.EConnectionType;
import org.talend.core.model.process.EParameterFieldType;
import org.talend.core.model.process.ElementParameterParser;
import org.talend.core.model.process.IConnection;
import org.talend.core.model.process.IElementParameter;
import org.talend.core.model.process.INode;
import com.ibm.icu.util.StringTokenizer;
/**
* This class will test an expression in the element parameters. <br>
* The expression can be for example: <br>
* ((VAR1 == 'value1' and VAR2 == 'value2') or (VAR3 != 'value3')) or (VAR4 == 'value4') <br>
* With VAR1, VAR2, VAR3 & VAR4 as the name of differents parameters and 'value1'.. the values to test. (values must be
* between quotes)<br>
*
* $Id: Expression.java 77219 2012-01-24 01:14:15Z mhirt $
*
*/
public final class Expression {
private Expression leftExpression;
private Expression rightExpression;
private String condition; // and / or
private String expressionString;
private boolean valid;
private static final String AND = "and"; //$NON-NLS-1$
private static final String OR = "or"; //$NON-NLS-1$
private static final String EQUALS = "=="; //$NON-NLS-1$
private static final String NOT_EQUALS = "!="; //$NON-NLS-1$
// private static ElementParameter currentParam;
private Expression(String expressionString) {
this.expressionString = expressionString;
}
private String getExpressionString() {
return this.expressionString;
}
private void setExpressionString(String value) {
this.expressionString = value;
}
private String getCondition() {
return this.condition;
}
private void setCondition(String condition) {
this.condition = condition;
}
private Expression getLeftExpression() {
return this.leftExpression;
}
private void setLeftExpression(Expression leftExpression) {
this.leftExpression = leftExpression;
}
private Expression getRightExpression() {
return this.rightExpression;
}
private void setRightExpression(Expression rightExpression) {
this.rightExpression = rightExpression;
}
private boolean isValid() {
return this.valid;
}
private void setValid(boolean value) {
this.valid = value;
}
public static boolean evaluate(final String string, List<? extends IElementParameter> listParam) {
return evaluate(string, listParam, null);
}
public static boolean evaluate(final String string, List<? extends IElementParameter> listParam, ElementParameter curParam) {
// currentParam = curParam;
if (string.contains("(") //$NON-NLS-1$
&& (isThereCondition(string, AND) || isThereCondition(string, OR))) {
return evaluateExpression(new Expression(string), listParam, curParam).isValid();
} else {
String newValue; // remove brackets
newValue = string.replace("(", ""); //$NON-NLS-1$ //$NON-NLS-2$
newValue = newValue.replace(")", ""); //$NON-NLS-1$ //$NON-NLS-2$
return evaluateSimpleExpression(newValue, listParam, curParam);
}
}
public static boolean isThereCondition(String expression, String condition) {
// example for the reg exp: (.*)[')][ ]*or[ ]*[\w(](.*)
String refixReg = "(.*)[') ][ ]*"; //$NON-NLS-1$
String suffixReg = "[ ]*[ (](.*)"; //$NON-NLS-1$
if (expression.matches(refixReg + condition + suffixReg)) {
return true;
}
if (expression.matches(refixReg + condition.toUpperCase() + suffixReg)) {
return true;
}
return false;
}
private static boolean evaluateSimpleExpression(String simpleExpression, List<? extends IElementParameter> listParam,
ElementParameter currentParam) {
boolean showParameter = false;
String test = null;
if (simpleExpression.contains(EQUALS)) {
test = EQUALS;
} else {
if (simpleExpression.contains(NOT_EQUALS)) {
test = NOT_EQUALS;
}
}
String[] strings = null;
if (test != null) {
strings = simpleExpression.split(test);
} else {
strings = new String[] { simpleExpression };
}
String variableName = null, variableValue = null;
for (int i = 0; i < strings.length; i++) {
String string = strings[i].trim();
if (string.contains("'")) { // value //$NON-NLS-1$
variableValue = string;
variableValue = variableValue.substring(1, string.lastIndexOf("'")); //$NON-NLS-1$
} else {
variableName = string;
}
}
/*
* this is only for Current OS condition.
*/
if (variableName != null && EParameterName.CURRENT_OS.getName().equals(variableName)) {
if (variableValue != null) {
if (checkCurrentOS(variableValue) && EQUALS.endsWith(test)) {
return true;
} else if (NOT_EQUALS.equals(test)) {
return true;
}
}
}
if (listParam == null) {
return false;
}
// 3 levels of variable name accepted maximum (ex: MY_VAR.TABLE.FIELD == 'test')
String[] varNames;
StringTokenizer token = new StringTokenizer(variableName, "."); //$NON-NLS-1$
varNames = StringUtils.split(variableName, '.');
// wyang: only for bug:9055, to search the related Node, for example tFTPGet wants to check tFTPConnection info
// variableName like: #LINK@NODE.CONNECTION.SFTP ----->it is a checkbox in tFTPConnection
// #LINK@NODE, #PREVIOUS@NODE, #NEXT@NODE ----->implement them later
if ((variableName != null) && (variableValue != null)) {
if (varNames[0].equals("#LINK@NODE")) {
if (currentParam != null && currentParam.getElement() instanceof INode) {
INode node = (INode) currentParam.getElement();
String relatedNodeName = ElementParameterParser.getValue(node, "__" + varNames[1] + "__");
List<? extends INode> generatingNodes = node.getProcess().getGeneratingNodes();
for (INode aNode : generatingNodes) {
if (aNode.getUniqueName().equals(relatedNodeName)) {
simpleExpression = simpleExpression.replace(varNames[0] + "." + varNames[1] + ".", "");
List<? extends IElementParameter> elementParameters = aNode.getElementParameters();
// let's supose the currentParam = null, there won't want deal with the TABLE field, only
// deal with LIST/CHECKBOX
return evaluate(simpleExpression, elementParameters);
}
}
}
}
}
if ((variableName != null) && (variableValue != null)) {
for (IElementParameter param : listParam) {
if (param.getName().equals(varNames[0])) {
IElementParameter testedParameter = param;
Object value = null;
boolean found = false;
if (param.getFieldType().equals(EParameterFieldType.TABLE)) {
List<Map<String, Object>> tableValues = (List<Map<String, Object>>) param.getValue();
if (currentParam == null) {
continue;
}
Map<String, Object> currentRow = tableValues.get(currentParam.getCurrentRow());
if (currentRow.containsKey(varNames[1])) {
for (Object curObj : param.getListItemsValue()) {
if (curObj instanceof IElementParameter) {
IElementParameter testParam = (IElementParameter) curObj;
if (testParam.getName().equals(varNames[1])) {
testedParameter = testParam;
break;
}
}
}
if (varNames.length == 2) { // simple value
value = currentRow.get(varNames[1]);
} else {
if ("TYPE".equals(varNames[2])) { //$NON-NLS-1$
IMetadataTable baseTable = null;
IMetadataColumn baseColumn = null;
INode node;
Object obj = currentRow.get(testedParameter.getName());
String columnName = ""; //$NON-NLS-1$
if (obj instanceof String) {
columnName = (String) obj;
} else if (obj instanceof Integer) {
columnName = testedParameter.getListItemsDisplayName()[(Integer) obj];
}
if (currentParam.getElement() instanceof INode) {
node = (INode) currentParam.getElement();
switch (testedParameter.getFieldType()) {
case COLUMN_LIST:
baseTable = node.getMetadataList().get(0);
break;
case PREV_COLUMN_LIST:
IConnection connection = null;
for (int i = 0; i < node.getIncomingConnections().size(); i++) {
IConnection curConnec = node.getIncomingConnections().get(i);
if (curConnec.getLineStyle() == EConnectionType.FLOW_MAIN) {
connection = curConnec;
break;
}
}
if (connection != null) {
baseTable = connection.getMetadataTable();
}
break;
case LOOKUP_COLUMN_LIST:
List<IConnection> refConnections = new ArrayList<IConnection>();
for (int i = 0; i < node.getIncomingConnections().size(); i++) {
IConnection curConnec = node.getIncomingConnections().get(i);
if (curConnec.getLineStyle() == EConnectionType.FLOW_REF) {
refConnections.add(curConnec);
}
}
for (IConnection curConnec : refConnections) {
IMetadataTable table = curConnec.getMetadataTable();
for (IMetadataColumn column : table.getListColumns()) {
String name = curConnec.getName() + "." + column.getLabel(); //$NON-NLS-1$
if (name.equals(columnName)) {
baseColumn = column;
}
}
}
break;
default:
}
if (baseTable != null) {
for (IMetadataColumn column : baseTable.getListColumns()) {
if (column.getLabel().equals(columnName)) {
baseColumn = column;
break;
}
}
}
if (baseColumn != null) {
switch (LanguageManager.getCurrentLanguage()) {
case JAVA:
value = JavaTypesManager.getTypeToGenerate(baseColumn.getTalendType(),
baseColumn.isNullable());
break;
default:
value = baseColumn.getTalendType();
}
if (value.equals(variableValue)) {
found = true;
}
}
}
}
}
}
} else if (param.getFieldType().equals(EParameterFieldType.PROPERTY_TYPE)
|| param.getFieldType().equals(EParameterFieldType.SCHEMA_TYPE)
|| param.getFieldType().equals(EParameterFieldType.QUERYSTORE_TYPE)
|| param.getFieldType().equals(EParameterFieldType.ENCODING_TYPE)) {
boolean child = false;
Map<String, IElementParameter> childParameters = param.getChildParameters();
if ("PROPERTY".equals(param.getName())) {
if (childParameters != null) {
IElementParameter iElementParameter = childParameters.get("PROPERTY_TYPE");
if (iElementParameter != null) {
Object value2 = iElementParameter.getValue();
if (variableValue.equals(value2.toString())) {
child = true;
found = true;
value = value2.toString();
}
}
}
}
if (varNames.length > 1 && varNames[1] != null) {
IElementParameter tempParam = childParameters.get(varNames[1]);
if (tempParam != null) {
value = tempParam.getValue();
if (value.equals(variableValue)) {
found = true;
}
child = true;
}
}
if (!child) {
value = testedParameter.getValue();
}
} else {
value = testedParameter.getValue();
}
if (value instanceof Integer) {
if (((Integer) value) < testedParameter.getListItemsValue().length) {
value = testedParameter.getListItemsValue()[(Integer) value];
}
}
if (value instanceof String) {
if (testedParameter.getListItemsValue() instanceof Object[]) {
Object[] values = (Object[]) testedParameter.getListItemsValue();
for (int i = 0; i < values.length && !found; i++) {
if (values[i].equals(value)) {
String variableCode = testedParameter.getListItemsDisplayCodeName()[i];
if (variableCode.equals(variableValue)) {
found = true;
}
}
}
}
} else if (value instanceof Boolean) {
Boolean tmpValue = new Boolean(variableValue);
if (tmpValue.equals(value)) {
found = true;
}
}
if (found) {
if (test.equals(EQUALS)) {
showParameter = true;
}
} else {
if (test.equals(NOT_EQUALS)) {
showParameter = true;
}
}
}
}
}
return showParameter;
}
private static Expression evaluateExpression(Expression expression, List<? extends IElementParameter> listParam,
ElementParameter currentParam) {
int indexBegining = 0, indexEnd;
int expressionLevel = 0;
String string = expression.getExpressionString();
boolean conditionFound = false;
// if there's no braket then there should be only simple expression
// or only one expression.
for (int i = 0; i < string.length() && !conditionFound; i++) {
if (string.charAt(i) == '(') {
if (expressionLevel == 0) {
indexBegining = i + 1;
}
expressionLevel++;
} else if (string.charAt(i) == ')') {
expressionLevel--;
indexEnd = i;
if (expressionLevel == 0) {
if (isThereCondition(string, AND) || isThereCondition(string, OR)) {
String leftString = string.substring(indexBegining, indexEnd).trim();
if (isThereCondition(leftString, AND) || isThereCondition(leftString, OR)) {
Expression leftExpression = new Expression(leftString);
expression.setLeftExpression(leftExpression);
evaluateExpression(leftExpression, listParam, currentParam);
} else {
Expression leftExpression = new Expression(leftString);
expression.setLeftExpression(leftExpression);
leftExpression.setValid(evaluateSimpleExpression(leftString, listParam, currentParam));
// debug: System.out.println(leftString + " => " +
// leftExpression.isValid());
}
} else {
String newValue; // remove brackets
newValue = string.replace("(", ""); //$NON-NLS-1$ //$NON-NLS-2$
newValue = newValue.replace(")", ""); //$NON-NLS-1$ //$NON-NLS-2$
expression.setExpressionString(newValue);
expression.setValid(evaluateSimpleExpression(newValue, listParam, currentParam));
}
}
} else if (expressionLevel == 0) {
if ((string.indexOf(AND, i) == i) || (string.indexOf(AND.toUpperCase(), i) == i)) {
String subStr = string.substring(i - 3, i + 5);
if (isThereCondition(subStr, AND)) {
expression.setCondition(AND);
conditionFound = true;
}
} else if ((string.indexOf(OR, i) == i) || (string.indexOf(OR.toUpperCase(), i) == i)) {
String subStr = string.substring(i - 3, i + 5);
if (isThereCondition(subStr, OR)) {
expression.setCondition(OR);
conditionFound = true;
}
}
}
if (conditionFound) {
if (expression.getLeftExpression() == null) { // no bracket ==
// evaluate
// expression
String leftString = string.substring(0, i - 1).trim();
Expression leftExpression = new Expression(leftString);
expression.setLeftExpression(leftExpression);
leftExpression.setValid(evaluateSimpleExpression(leftString, listParam, currentParam));
// debug: System.out.println(leftString + " => " +
// leftExpression.isValid());
}
String rightString = string.substring(i + 3, string.length()).trim();
Expression rightExpression = new Expression(rightString);
expression.setRightExpression(rightExpression);
if (rightString.contains("(") //$NON-NLS-1$
|| isThereCondition(rightString, AND) || isThereCondition(rightString, OR)) {
evaluateExpression(rightExpression, listParam, currentParam);
} else { // no bracket == evaluate expression
rightExpression.setValid(evaluateSimpleExpression(rightString, listParam, currentParam));
// debug: System.out.println(rightString + " => " +
// rightExpression.isValid());
}
if (expression.getCondition().equals(AND)) {
if (expression.getLeftExpression().isValid() && expression.getRightExpression().isValid()) {
expression.setValid(true);
} else {
expression.setValid(false);
}
} else if (expression.getCondition().equals(OR)) {
if (expression.getLeftExpression().isValid() || expression.getRightExpression().isValid()) {
expression.setValid(true);
} else {
expression.setValid(false);
}
}
}
}
// if after an expression between bracket there's no other expression,
// then the validation of the expression
// will depends on the "left" expression.
if ((expression.getRightExpression() == null) && (expression.getLeftExpression() != null)) {
expression.setValid(expression.getLeftExpression().isValid());
}
// debug: System.out.println(expression.getExpressionString() + " => " +
// expression.isValid());
return expression;
}
/*
* check this OS
*/
private static boolean checkCurrentOS(final String osName) {
if (osName == null) {
return false;
}
final String tmpOSName = osName.toLowerCase();
// check windows
if (EnvironmentUtils.isWindowsSystem() && tmpOSName.startsWith("windows")) { //$NON-NLS-1$
return true;
}
// check MacOS
if (EnvironmentUtils.isMacOsSytem() && tmpOSName.startsWith("mac")) { //$NON-NLS-1$
return true;
}
// check linux and unix
if (EnvironmentUtils.isLinuxUnixSystem()) {
if (tmpOSName.startsWith("unix") || tmpOSName.startsWith("linux")) { //$NON-NLS-1$ //$NON-NLS-2$
return true;
}
}
return false;
}
}