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

com.sap.gateway.v4.rt.jdbc.hana.HanaExpressionVisitor Maven / Gradle / Ivy

package com.sap.gateway.v4.rt.jdbc.hana;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import org.apache.olingo.commons.api.edm.EdmEnumType;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
import org.apache.olingo.server.api.uri.UriResourceProperty;
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
import org.apache.olingo.server.api.uri.queryoption.expression.Literal;
import org.apache.olingo.server.api.uri.queryoption.expression.Member;
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HanaExpressionVisitor implements ExpressionVisitor {
	
	final static Logger logger=LoggerFactory.getLogger(HanaExpressionVisitor.class);

	
	public HanaExpressionVisitor() {
		// TODO Auto-generated constructor stub
	}


	@Override
	public Object visitBinaryOperator(BinaryOperatorKind operator, Object left, Object right)
			throws ExpressionVisitException, ODataApplicationException {
		 // Binary Operators are split up in three different kinds. Up to the kind of the
	    // operator it can be applied to different types
	    //   - Arithmetic operations like add, minus, modulo, etc. are allowed on numeric
	    //     types like Edm.Int32
	    //   - Logical operations are allowed on numeric types and also Edm.String
	    //   - Boolean operations like and, or are allowed on Edm.Boolean
	    // A detailed explanation can be found in OData Version 4.0 Part 2: URL Conventions
		String leftString;
		if(left instanceof Number || operator==BinaryOperatorKind.AND||operator==BinaryOperatorKind.OR){
			leftString=left.toString();
		}else{
			leftString="\""+left.toString()+"\"";
		}
		StringBuffer buffer = new StringBuffer(leftString);
		switch(operator){
		case GT:
			buffer.append(' ').append('>').append(' ');
			break;
		case LT:
			buffer.append(' ').append('<').append(' ');
			break;
		case EQ:
			if(buffer.indexOf("LIKE") < 0){
				buffer.append(' ').append('=').append(' ');
			}
			break;
		case NE:
			buffer.append(' ').append("<>").append(' ');
			break;
		case LE:
			buffer.append(' ').append("<=").append(' ');
			break;
		case GE:
			buffer.append(' ').append(">=").append(' ');
			break;
		case AND:
			buffer.append(' ').append(operator.toString()).append(' ');
			break;
		case OR:
			buffer.append(' ').append(operator.toString()).append(' ');
			break;
		default:
			throw new ODataApplicationException("Operator " + operator + " not implemented",
			          HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);
	}
		String rightSide=right.toString();
		

		if ((rightSide.contains("datetimeoffset'")) || (rightSide.contains("datetime'")) || (rightSide.contains("PT") && rightSide.contains("S") && rightSide.contains("H") && rightSide.contains("M"))){
			buffer.append(evaluateComparingExpression(rightSide));
		}
		else {
			if(buffer.indexOf("LIKE") < 0 || operator != BinaryOperatorKind.EQ)
				buffer.append(right);
			else
				if(rightSide.equals("false")){
					String newBuffer = buffer.toString().replaceFirst(" LIKE ", " NOT LIKE ");
					buffer = new StringBuffer(newBuffer);
			}
		}
		
	    //buffer.append(right);
	    return buffer.toString();
	}

	@Override
	public Object visitUnaryOperator(UnaryOperatorKind operator, Object operand)
			throws ExpressionVisitException, ODataApplicationException {
		  // OData allows two different unary operators. We have to take care, that the type of the
	    // operand fits to the operand

	    if(operator == UnaryOperatorKind.NOT && operand instanceof Boolean) {
	      // 1.) boolean negation
	      return !(Boolean) operand;
	    } else if(operator == UnaryOperatorKind.MINUS && operand instanceof Integer){
	      // 2.) arithmetic minus
	      return -(Integer) operand;
	    }

	    // Operation not processed, throw an exception
	    throw new ODataApplicationException("Invalid type for unary operator",
	        HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ENGLISH);
	}

	@Override
	public Object visitMethodCall(MethodKind methodCall, List parameters)
			throws ExpressionVisitException, ODataApplicationException {
		 // To keep this tutorial small and simple, we implement only one method call
	    // contains(String, String) -> Boolean
	    if(methodCall == MethodKind.CONTAINS) {
	      if(parameters.get(0) instanceof String && parameters.get(1) instanceof String) {
	        String valueParam1 = (String) parameters.get(0);
	        String valueParam2 = (String) parameters.get(1);

	        return valueParam1.contains(valueParam2);
	      } else {
	        throw new ODataApplicationException("Contains needs two parametes of type Edm.String",
	            HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ENGLISH);
	      }
	    } else {
	      throw new ODataApplicationException("Method call " + methodCall + " not implemented",
	          HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);
	    }
	}

	@Override
	public Object visitLambdaExpression(String lambdaFunction, String lambdaVariable, Expression expression)
			throws ExpressionVisitException, ODataApplicationException {
		// TODO Auto-generated method stub
		return null;
	}

	/*@Override
	public Object visitLiteral(String literal) throws ExpressionVisitException, ODataApplicationException {
		return literal;
	
	}*/

	@Override
	public Object visitMember(Member member) throws ExpressionVisitException, ODataApplicationException {
		 if (member.getResourcePath().getUriResourceParts().size() == 1) {
		        UriResourcePrimitiveProperty property
		                                 = (UriResourcePrimitiveProperty)
		                                              member.getResourcePath().getUriResourceParts().get(0);
		        return property.getProperty().getName();
		    } else {
		        List propertyNames = new ArrayList();
		        for (UriResource property : member.getResourcePath().getUriResourceParts()) {
		            UriResourceProperty primitiveProperty
		                                  = (UriResourceProperty) property;
		            propertyNames.add(primitiveProperty.getProperty().getName());
		        }
		        return propertyNames;
		    }
	}

	@Override
	public Object visitAlias(String aliasName) throws ExpressionVisitException, ODataApplicationException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object visitTypeLiteral(EdmType type) throws ExpressionVisitException, ODataApplicationException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object visitLambdaReference(String variableName) throws ExpressionVisitException, ODataApplicationException {
		throw new ODataApplicationException("Lambda Expression not implemented",
		          HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);
	}

	@Override
	public Object visitEnum(EdmEnumType type, List enumValues)
			throws ExpressionVisitException, ODataApplicationException {
		throw new ODataApplicationException("Enum Filters not implemented",
		          HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH);
	}

	@Override
	public Object visitLiteral(Literal literal) throws ExpressionVisitException, ODataApplicationException {
		return literal.getText();
		
	}

	
	public String evaluateComparingExpression(String value) {

	    if(value.contains("datetime") && !value.contains("datetimeoffset")) {
	      
	    	value = value.substring(9, value.length()-1);
	    	Calendar cal = Calendar.getInstance();
			Date date;
			
			date = parseDate(value);
		/*	long dbTime = date.getTime();
		    Date originalDate = new Date(dbTime + TimeZone.getDefault().getOffset(dbTime));*/
		    		    
			if(date!=null){
			cal.setTime(date);
			}

	        String year = String.format("%04d", cal.get(Calendar.YEAR));
	        String month = String.format("%02d", cal.get(Calendar.MONTH) + 1);
	        String day = String.format("%02d", cal.get(Calendar.DAY_OF_MONTH));
	        String hour = String.format("%02d", cal.get(Calendar.HOUR_OF_DAY));
	        String min = String.format("%02d", cal.get(Calendar.MINUTE));
	        String sec = String.format("%02d", cal.get(Calendar.SECOND));
	        	        
	        value = "\'" + year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec + "\'";
	    
	    }
	    else if(value.contains("datetimeoffset")) {
	    	value = value.substring(15, value.length()-1);
	    	Calendar cal = Calendar.getInstance();
			Date date;
			
			date = parseDate(value);
			/*long dbTime = date.getTime();
		    Date originalDate = new Date(dbTime + TimeZone.getDefault().getOffset(dbTime));*/
		    		    
			if(date!=null){
			cal.setTime(date);
			}

	        String year = String.format("%04d", cal.get(Calendar.YEAR));
	        String month = String.format("%02d", cal.get(Calendar.MONTH) + 1);
	        String day = String.format("%02d", cal.get(Calendar.DAY_OF_MONTH));
	        String hour = String.format("%02d", cal.get(Calendar.HOUR_OF_DAY));
	        String min = String.format("%02d", cal.get(Calendar.MINUTE));
	        String sec = String.format("%02d", cal.get(Calendar.SECOND));
	        String offset = "";
	        
	        if(value.contains("+")) {
	        	offset = value.substring(value.indexOf('+') , value.length());
	        } else if(value.contains("-")) {
	        	offset = value.substring(value.lastIndexOf('-') , value.length());	        	
		    }
	        
	        value = "\'" + year + "-" + month + "-" + day + " " + hour + ":" + min + ":" + sec + offset + "\'";
	    	
	    	
	    }	    
	    else {
	    	
	    	String hourValue = String.format("%02d", Integer.parseInt(value.substring(7, value.indexOf('H'))));
	        String minValue = String.format("%02d", Integer.parseInt(value.substring(value.indexOf('H') + 1, value.indexOf('M'))));
	        String secValue = String.format("%02d", Integer.parseInt(value.substring(value.indexOf('M') + 1, value.indexOf('S'))));
	        
	        value = "\'" + hourValue + ":" + minValue + ":" + secValue + "\'";
	    	
	    }
	    
	    return value;
			
	  }
	
	
	public Date  parseDate(String dateValue) {
		 final String[] dateFormats = { 
			  //"yyyy-MM-dd'T'HH:mm:ss'Z'",   
				 "yyyy-MM-dd'T'HH:mm:ssZ",
	        "yyyy-MM-dd'T'HH:mm:ss",      //"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
	        /*"yyyy-MM-dd'T'HH:mm:ss.SSSZ", 
	        "yyyy-MM-dd",
	        "hh-mm-ss","hh:mm:ss"*/
		};
		Date date = null;
		if (dateValue != null) {
			for (String parse : dateFormats) {
				SimpleDateFormat sdf = new SimpleDateFormat(parse);
				try {
					date=sdf.parse(dateValue);
				} catch (ParseException e) {
					logger.debug("Failed DateFormat ::"+parse,e);
				}
			}
		}
		return date;
	}	
	
}