/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.translator.coherence.visitor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.teiid.language.AggregateFunction;
import org.teiid.language.ColumnReference;
import org.teiid.language.Comparison;
import org.teiid.language.Comparison.Operator;
import org.teiid.language.DerivedColumn;
import org.teiid.language.Expression;
import org.teiid.language.Function;
import org.teiid.language.In;
import org.teiid.language.Like;
import org.teiid.language.Literal;
import org.teiid.language.NamedTable;
import org.teiid.language.ScalarSubquery;
import org.teiid.language.SearchedCase;
import org.teiid.language.Select;
import org.teiid.language.TableReference;
import org.teiid.language.visitor.HierarchyVisitor;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.metadata.Column;
import org.teiid.metadata.ForeignKey;
import org.teiid.metadata.RuntimeMetadata;
import org.teiid.metadata.Table;
import org.teiid.resource.adapter.coherence.CoherenceFilterUtil;
import org.teiid.translator.TranslatorException;
import org.teiid.translator.coherence.CoherencePlugin;
import com.tangosol.util.Filter;
/**
*/
public class CoherenceVisitor extends HierarchyVisitor {
private String tableName = null;
protected String[] attributeNames = null;
protected Class[] attributeTypes = null;
private RuntimeMetadata metadata;
private Filter filter = null;
private TranslatorException exception;
/**
*
*/
public CoherenceVisitor(RuntimeMetadata metadata) {
super();
this.metadata = metadata;
}
public Filter getFilter() {
return filter;
}
public String getTableName() {
return tableName;
}
public String[] getAttributeNames() {
return attributeNames;
}
public Class[] getAttributeTypes() {
return attributeTypes;
}
public TranslatorException getException() {
return this.exception;
}
public Filter createFilter(String criteria) throws TranslatorException {
return CoherenceFilterUtil.createFilter(criteria);
}
public void visit(Select query) {
super.visit(query);
Iterator<DerivedColumn> selectSymbolItr = query.getDerivedColumns().iterator();
attributeNames = new String[query.getDerivedColumns().size()];
attributeTypes = new Class[query.getDerivedColumns().size()];
int i=0;
while(selectSymbolItr.hasNext()) {
Column e = getElementFromSymbol(selectSymbolItr.next());
attributeNames[i] = this.getNameFromElement(e);
attributeTypes[i] = e.getJavaType();
i++;
}
List<TableReference> tables = query.getFrom();
TableReference t = tables.get(0);
if(t instanceof NamedTable) {
Table group = ((NamedTable)t).getMetadataObject();
tableName = group.getName();
}
}
public void visit(Comparison obj) {
LogManager.logTrace(LogConstants.CTX_CONNECTOR, "Parsing Comparison criteria."); //$NON-NLS-1$
try {
Comparison.Operator op = ((Comparison) obj).getOperator();
Expression lhs = ((Comparison) obj).getLeftExpression();
Expression rhs = ((Comparison) obj).getRightExpression();
String lhsString = getExpressionString(lhs);
String rhsString = getExpressionString(rhs);
if(lhsString == null || rhsString == null) {
final String msg = CoherencePlugin.Util.getString("CoherenceVisitor.missingComparisonExpression"); //$NON-NLS-1$
exception = new TranslatorException(msg);
}
if (rhs instanceof Literal || lhs instanceof Literal) {
if(rhs instanceof Literal) {
Literal literal = (Literal) rhs;
addCompareCriteria(lhsString, literal.getValue(), op, literal.getType() );
// filter = CoherenceFilterUtil.createCompareFilter(lhsString, literal.getValue(), op, literal.getType() );
} else {
Literal literal = (Literal) lhs;
addCompareCriteria(rhsString, literal.getValue(), op, literal.getType() );
// filter = CoherenceFilterUtil.createCompareFilter(rhsString, literal.getValue(), op, literal.getType() );
}
}
}catch (TranslatorException t) {
exception = t;
}
}
public void addCompareCriteria(String columnname, Object value, Operator op, Class<?> type ) throws TranslatorException {
filter = CoherenceFilterUtil.createCompareFilter(columnname, value, op, type);
}
public void visit(Like obj) {
LogManager.logTrace(LogConstants.CTX_CONNECTOR, "Parsing LIKE criteria."); //$NON-NLS-1$
// isNegated = ((Like) criteria).isNegated();
// Convert LIKE to Equals, where any "%" symbol is replaced with "*".
try {
Comparison.Operator op = Operator.EQ;
Expression lhs = ((Like) obj).getLeftExpression();
Expression rhs = ((Like) obj).getRightExpression();
String lhsString = getExpressionString(lhs);
String rhsString = getExpressionString(rhs);
// rhsString = rhsString.replace("%", "*"); //$NON-NLS-1$ //$NON-NLS-2$
filter = CoherenceFilterUtil.createFilter(lhsString + " LIKE \'" + rhsString + "\'");
}catch (TranslatorException t) {
exception = t;
}
}
public void visit(In obj) {
LogManager.logTrace(LogConstants.CTX_CONNECTOR, "Parsing IN criteria."); //$NON-NLS-1$
// isNegated = ((In) criteria).isNegated();
try {
Expression lhs = ((In)obj).getLeftExpression();
String lhsString = getExpressionString(lhs);
List<Expression> rhsList = ((In)obj).getRightExpressions();
Class type = null;
List parms = new ArrayList(rhsList.size());
Iterator iter = rhsList.iterator();
while(iter.hasNext()) {
Expression expr = (Expression) iter.next();
type = addParmFromExpression(expr, parms);
}
addInCriteria(lhsString, parms, type);
// filter = CoherenceFilterUtil.createInFilter(lhsString, parms, type);
}catch (TranslatorException t) {
exception = t;
}
}
public void addInCriteria(String columnname, List<Object> parms, Class<?> type ) throws TranslatorException {
filter = CoherenceFilterUtil.createInFilter(columnname, parms, type);
}
private Class addParmFromExpression(Expression expr, List parms ) {
Class type = null;
if(expr instanceof Literal) {
Long longparm = null;
Literal literal = (Literal) expr;
parms.add(literal);
type = literal.getType();
} else {
this.exception = new TranslatorException("CoherenceVisitor.Unsupported_expression" + expr); //$NON-NLS-1$
}
return type;
}
/**
* Method to get name from the supplied Element
* @param e the supplied Element
* @return the name
*/
// GHH 20080326 - found that code to fall back on Name if NameInSource
// was null wasn't working properly, so replaced with tried and true
// code from another custom connector.
public String getNameFromElement(Column e) {
String attributeName = null;
Object p = e.getParent();
if (p instanceof Table) {
Table t = (Table)p;
if (t.getForeignKeys() != null && !t.getForeignKeys().isEmpty()) {
ForeignKey fk = (ForeignKey) t.getForeignKeys().get(0);
String fk_nis = fk.getNameInSource();
attributeName = fk_nis + "." + e.getNameInSource();
}
}
if (attributeName == null) {
attributeName = e.getNameInSource();
}
if (attributeName == null || attributeName.equals("")) { //$NON-NLS-1$
attributeName = e.getName();
// If name in source is not set, then fall back to the column name.
}
return attributeName;
}
public String getNameFromTable(Table e) {
String tableName = e.getNameInSource();
if (tableName == null || tableName.equals("")) { //$NON-NLS-1$
tableName = e.getName();
// If name in source is not set, then fall back to the column name.
}
return tableName;
}
/**
* Helper method for getting runtime {@link org.teiid.connector.metadata.runtime.Element} from a
* {@link org.teiid.language.DerivedColumn}.
* @param symbol Input ISelectSymbol
* @return Element returned metadata runtime Element
*/
private Column getElementFromSymbol(DerivedColumn symbol) {
ColumnReference expr = (ColumnReference) symbol.getExpression();
return expr.getMetadataObject();
}
// GHH 20080326 - found that code to fall back on Name if NameInSource
// was null wasn't working properly, so replaced with tried and true
// code from another custom connector.
private String getExpressionString(Expression e) throws TranslatorException {
String expressionName = null;
// GHH 20080326 - changed around the IElement handling here
// - the rest of this method is unchanged
if(e instanceof ColumnReference) {
Column mdIDElement = ((ColumnReference)e).getMetadataObject();
expressionName = mdIDElement.getNameInSource();
if(expressionName == null || expressionName.equals("")) { //$NON-NLS-1$
expressionName = mdIDElement.getName();
}
} else if(e instanceof Literal) {
// try {
// if(((Literal)e).getType().equals(Class.forName(Timestamp.class.getName()))) {
// LogManager.logTrace(LogConstants.CTX_CONNECTOR, "Found an expression that uses timestamp; converting to LDAP string format."); //$NON-NLS-1$
// Timestamp ts = (Timestamp)((Literal)e).getValue();
// Date dt = new Date(ts.getTime());
// //TODO: Fetch format if provided.
// SimpleDateFormat sdf = new SimpleDateFormat(LDAPConnectorConstants.ldapTimestampFormat);
// expressionName = sdf.format(dt);
// LogManager.logTrace(LogConstants.CTX_CONNECTOR, "Timestamp to stsring is: " + expressionName); //$NON-NLS-1$
// }
// else {
// expressionName = ((Literal)e).getValue().toString();
// }
expressionName = ((Literal)e).getValue().toString();
// } catch (ClassNotFoundException cce) {
// final String msg = LDAPPlugin.Util.getString("IQueryToLdapSearchParser.timestampClassNotFoundError"); //$NON-NLS-1$
// throw new TranslatorException(cce, msg);
// }
//
} else {
if(e instanceof AggregateFunction) {
LogManager.logError(LogConstants.CTX_CONNECTOR, "Received IAggregate, but it is not supported. Check capabilities."); //$NON-NLS-1$
} else if(e instanceof Function) {
LogManager.logError(LogConstants.CTX_CONNECTOR, "Received IFunction, but it is not supported. Check capabilties."); //$NON-NLS-1$
} else if(e instanceof ScalarSubquery) {
LogManager.logError(LogConstants.CTX_CONNECTOR, "Received IScalarSubquery, but it is not supported. Check capabilties."); //$NON-NLS-1$
} else if (e instanceof SearchedCase) {
LogManager.logError(LogConstants.CTX_CONNECTOR, "Received ISearchedCaseExpression, but it is not supported. Check capabilties."); //$NON-NLS-1$
}
final String msg = CoherencePlugin.Util.getString("CoherenceVisitory.unsupportedElementError" , e.toString()); //$NON-NLS-1$
throw new TranslatorException(msg);
}
expressionName = escapeReservedChars(expressionName);
return expressionName;
}
private String escapeReservedChars(String expr) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < expr.length(); i++) {
char curChar = expr.charAt(i);
switch (curChar) {
case '\\':
sb.append("\\5c"); //$NON-NLS-1$
break;
case '*':
sb.append("\\2a"); //$NON-NLS-1$
break;
case '(':
sb.append("\\28"); //$NON-NLS-1$
break;
case ')':
sb.append("\\29"); //$NON-NLS-1$
break;
case '\u0000':
sb.append("\\00"); //$NON-NLS-1$
break;
default:
sb.append(curChar);
}
}
return sb.toString();
}
}