com.impetus.kundera.query.KunderaQueryParser Maven / Gradle / Ivy
/*******************************************************************************
* * Copyright 2012 Impetus Infotech.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
******************************************************************************/
package com.impetus.kundera.query;
import java.util.ListIterator;
import java.util.StringTokenizer;
import org.apache.commons.lang.StringUtils;
import org.eclipse.persistence.jpa.jpql.parser.CollectionExpression;
import org.eclipse.persistence.jpa.jpql.parser.Expression;
import org.eclipse.persistence.jpa.jpql.parser.FromClause;
import org.eclipse.persistence.jpa.jpql.parser.GroupByClause;
import org.eclipse.persistence.jpa.jpql.parser.HavingClause;
import org.eclipse.persistence.jpa.jpql.parser.IdentificationVariable;
import org.eclipse.persistence.jpa.jpql.parser.OrderByClause;
import org.eclipse.persistence.jpa.jpql.parser.ResultVariable;
import org.eclipse.persistence.jpa.jpql.parser.SelectClause;
import org.eclipse.persistence.jpa.jpql.parser.StateFieldPathExpression;
import org.eclipse.persistence.jpa.jpql.parser.WhereClause;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Parser for handling JPQL Single-String queries. Takes a JPQLQuery and the
* query string and parses it into its constituent parts, updating the JPQLQuery
* accordingly with the result that after calling the parse() method the
* JPQLQuery is populated.
*
*
* SELECT [ {result} ]
* [FROM {candidate-classes} ]
* [WHERE {filter}]
* [GROUP BY {grouping-clause} ]
* [HAVING {having-clause} ]
* [ORDER BY {ordering-clause}]
* e.g SELECT c FROM Customer c INNER JOIN c.orders o WHERE c.status = 1
*
*
* @author animesh.kumar
*/
public class KunderaQueryParser
{
/** The JPQL query to populate. */
private KunderaQuery query;
/** The single-string query string. */
private String queryString;
/** The logger. */
private static Logger logger = LoggerFactory.getLogger(KunderaQueryParser.class);
/**
* Constructor for the Single-String parser.
*
* @param query
* The query
* @param queryString
* The Single-String query
*/
public KunderaQueryParser(KunderaQuery query)
{
this.query = query;
this.queryString = query.getJPAQuery();
}
/**
* Method to parse the Single-String query.
*/
public final void parse()
{
new Compiler().compile();
}
/**
* Method to detect whether this token is a keyword for JPQL Single-String.
*
* @param token
* The token
*
* @return Whether it is a keyword
*/
private boolean isKeyword(String token)
{
// Compare the passed token against the provided keyword list, or their
// lowercase form
for (int i = 0; i < KunderaQuery.SINGLE_STRING_KEYWORDS.length; i++)
{
if (token.equalsIgnoreCase(KunderaQuery.SINGLE_STRING_KEYWORDS[i]))
{
return true;
}
}
return false;
}
/**
* Compiler to process keywords contents. In the query the keywords often
* have content values following them that represent the constituent parts
* of the query. This takes the keyword and sets the constituent part
* accordingly.
*/
private class Compiler
{
// Temporary variable since grouping clause is made up of GROUP BY ...
// HAVING ...
/** The grouping clause. */
private String groupingClause;
/**
* Compile.
*/
private void compile()
{
// if it is not an update statement
if (!compileUpdate())
{
compileSelectOrDelete();
}
}
/**
* Compile update.
*
* @return true, if successful
*/
private boolean compileUpdate()
{
if (query.isUpdateStatement())
{
query.setIsDeleteUpdate(true);
compileFrom();
compileUpdateClause();
compilewhereClause();
return true;
}
else
{
// initiateExpressionFactory("SELECT");
}
return false;
}
/**
* Compile select.
*/
private void compileSelectOrDelete()
{
if (!query.isSelectStatement())
{
if (query.isDeleteStatement())
{
query.setIsDeleteUpdate(true);
}
}
else
{
// initiateExpressionFactory("SELECT");
}
compileFrom();
compileResult();
compilewhereClause();
}
private boolean isWhereClause()
{
if (query.isSelectStatement())
{
return query.getSelectStatement().hasWhereClause();
}
else if (query.isUpdateStatement())
{
return query.getUpdateStatement().hasWhereClause();
}
if (query.isDeleteStatement())
{
return query.getDeleteStatement().hasWhereClause();
}
return false;
}
private boolean isGroupBy()
{
if (query.isSelectStatement())
{
return query.getSelectStatement().hasGroupByClause();
}
return false;
}
private boolean isHaving()
{
if (query.isSelectStatement())
{
return query.getSelectStatement().hasHavingClause();
}
return false;
}
private boolean isOrderBy()
{
if (query.isSelectStatement())
{
return query.getSelectStatement().hasOrderByClause();
}
return false;
}
/**
* Compilewhere clause.
*/
private void compilewhereClause()
{
if (isWhereClause())
{
compileWhere();
}
if (isGroupBy())
{
compileGroup();
}
if (isHaving())
{
compileHaving();
}
if (groupingClause != null)
{
query.setGrouping(groupingClause);
}
if (isOrderBy())
{
compileOrder();
}
}
/**
* Compile result.
*/
private void compileResult()
{
buildResultColumns();
}
/**
* Compile from.
*/
private void compileFrom()
{
buildFrom();
}
/**
* Compile from.
*/
private void compileUpdateClause()
{
ListIterator updateColumnIter = null;
if (query.isUpdateStatement() && query.getUpdateStatement().getUpdateClause().hasUpdateItems())
{
if (query.getUpdateStatement().getUpdateClause().getUpdateItems() instanceof CollectionExpression)
{
updateColumnIter = ((CollectionExpression) query.getUpdateStatement().getUpdateClause()
.getUpdateItems()).children().iterator();
while (updateColumnIter.hasNext())
{
ListIterator childUpdateClauseIter = updateColumnIter.next().children().iterator();
while (childUpdateClauseIter.hasNext())
{
addUpdateClause(childUpdateClauseIter);
}
}
}
else
{
updateColumnIter = query.getUpdateStatement().getUpdateClause().getUpdateItems().children()
.iterator();
addUpdateClause(updateColumnIter);
}
}
}
private void addUpdateClause(ListIterator childUpdateClauseIter)
{
String columnTuple = childUpdateClauseIter.next().toActualText().trim();
String value = childUpdateClauseIter.next().toActualText().trim();
StringTokenizer tokenizer = new StringTokenizer(columnTuple, ".");
columnTuple = getTokenizedValue(tokenizer);
query.addUpdateClause(columnTuple, value);
}
private String getTokenizedValue(StringTokenizer tokenizer)
{
String value = null;
while (tokenizer.hasMoreTokens())
{
value = tokenizer.nextToken();
}
return value;
}
/**
* Compile where.
*/
private void compileWhere()
{
WhereClause whereClause = null;
if (query.isSelectStatement())
{
whereClause = (WhereClause) query.getSelectStatement().getWhereClause();
}
else if (query.isUpdateStatement())
{
whereClause = (WhereClause) query.getUpdateStatement().getWhereClause();
}
if (query.isDeleteStatement())
{
whereClause = (WhereClause) query.getDeleteStatement().getWhereClause();
}
String content = whereClause.getConditionalExpression().toActualText();
if (whereClause != null && content.length() == 0)
{
throw new JPQLParseException("keyword without value[WHERE]");
}
query.setFilter(content);
}
/**
* Compile group.
*/
private void compileGroup()
{
GroupByClause groupByClause = null;
if (query.isSelectStatement())
{
groupByClause = (GroupByClause) query.getSelectStatement().getGroupByClause();
}
// content cannot be empty
if (groupByClause == null && groupByClause.toActualText().length() == 0)
{
throw new JPQLParseException("keyword without value: GROUP BY");
}
groupingClause = groupByClause.toActualText();
}
/**
* Compile having.
*/
private void compileHaving()
{
HavingClause havingClause = null;
if (query.isSelectStatement())
{
havingClause = (HavingClause) query.getSelectStatement().getHavingClause();
}
// content cannot be empty
if (havingClause == null && havingClause.toActualText().length() == 0)
{
throw new JPQLParseException("keyword without value: HAVING");
}
if (groupingClause != null)
{
groupingClause = groupingClause.trim() + havingClause.toActualText();
}
else
{
groupingClause = havingClause.toActualText();
}
}
/**
* Compile order.
*/
private void compileOrder()
{
OrderByClause orderByClause = null;
if (query.isSelectStatement())
{
orderByClause = (OrderByClause) query.getSelectStatement().getOrderByClause();
}
if (orderByClause == null || !orderByClause.hasOrderByItems())
{
throw new JPQLParseException("keyword without value: ORDER BY");
}
query.setOrdering(orderByClause.getOrderByItems().toActualText());
}
}
private void buildResultColumns()
{
String[] result = null, aggResult = null;
if (query.isSelectStatement())
{
SelectClause selectClause = (SelectClause) (query.getSelectStatement().getSelectClause());
ListIterator selectColumnIter = null;
int size = 0;
if (selectClause.getSelectExpression() instanceof CollectionExpression)
{
CollectionExpression selectColumnExpression = (CollectionExpression) selectClause.getSelectExpression();
selectColumnIter = selectColumnExpression.children().iterator();
size = selectColumnExpression.childrenSize();
}
else
{
if (selectClause.getSelectExpression().toActualText().indexOf(".") > 0)
{
size = 1;
}
}
int aggregationCount = countAggregation(selectClause.getSelectExpression());
query.setAggregated(aggregationCount > 0 || query.getSelectStatement().hasGroupByClause());
int count = 0, aggCounter = 0, resultSize = size + 1 - aggregationCount;
if (resultSize == 0)
{
resultSize = 1;
}
result = new String[resultSize];
aggResult = new String[aggregationCount + 1];
// content may be empty
if (selectColumnIter != null)
{
while (selectColumnIter.hasNext())
{
Expression nextExpression = selectColumnIter.next();
String property = nextExpression.toActualText();
if (validateExpression(nextExpression))
{
aggCounter = buildResult(aggResult, aggCounter,
property.substring(property.indexOf('(') + 1, property.indexOf(')')));
}
else
count = buildResult(result, count, property);
}
}
else
{
String property = selectClause.getSelectExpression().toActualText();
if (validateExpression(selectClause.getSelectExpression()))
aggCounter = buildResult(aggResult, aggCounter,
property.substring(property.indexOf('(') + 1, property.indexOf(')')));
else
count = buildResult(result, count, property);
}
result[0] = result[0] == null ? aggResult[0] : result[0];
aggResult[0] = aggResult[0] == null ? result[0] : aggResult[0];
query.setResult(result);
query.setAggregationResult(aggResult);
}
}
/**
* @param selectExpression
* @return Count of aggregation required
*/
private int countAggregation(Expression selectExpression)
{
int count = 0;
if (selectExpression instanceof CollectionExpression)
{
CollectionExpression selectColumnExpression = (CollectionExpression) selectExpression;
ListIterator selectColumnIter = selectColumnExpression.children().iterator();
while (selectColumnIter.hasNext())
{
count = validateExpression(selectColumnIter.next()) ? ++count : count;
}
}
else
{
if (validateExpression(selectExpression))
count = 1;
}
return count;
}
private boolean validateExpression(Expression expression)
{
return !(expression instanceof StateFieldPathExpression || expression instanceof IdentificationVariable || expression instanceof ResultVariable);
}
private int buildResult(String[] result, int count, String property)
{
if (property != null && property.length() > 0)
{
if (property.indexOf(".") > 0)
{
result[0] = property.substring(0, property.indexOf("."));
String fieldName = property.substring(property.indexOf(".") + 1, property.length());
if (fieldName == null || fieldName.isEmpty())
{
throw new JPQLParseException(
"You have not given any column name after . ,Column name should not be empty");
}
if (result[count] == null)
{
throw new JPQLParseException("Bad query format");
}
result[++count] = fieldName;
}
else
{
if (count > 0)
{
throw new JPQLParseException("Bad query format");
}
result[count] = property;
count++;
}
}
return count;
}
private void buildFrom()
{
ListIterator fromIter = null;
if (query.isSelectStatement() && query.getSelectStatement().hasFromClause())
{
FromClause fromClause = (FromClause) query.getSelectStatement().getFromClause();
fromIter = fromClause.children().iterator();
}
else if (query.isUpdateStatement())
{
fromIter = query.getUpdateStatement().getUpdateClause().children().iterator();
}
if (query.isDeleteStatement())
{
fromIter = query.getDeleteStatement().getDeleteClause().children().iterator();
}
if (fromIter != null)
{
while (fromIter.hasNext())
{
String textObj = fromIter.next().toActualText().trim();
if (!StringUtils.isEmpty(textObj))
{
query.setFrom(textObj);
break;
}
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy