/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* 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.
*/
package com.liferay.poshi.runner.pql;
import com.liferay.poshi.runner.util.ListUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
/**
* @author Michael Hashimoto
*/
public class PQLQuery extends PQLEntity {
public static boolean isQuery(String pql) {
if (pql == null) {
return false;
}
pql = removeModifierFromPQL(pql);
String[] queryTokens = _getQueryTokens(pql);
if (queryTokens == null) {
return false;
}
return true;
}
public PQLQuery(String query) throws Exception {
super(query);
_validateQuery(query);
String[] queryTokens = _getQueryTokens(getPQL());
_pqlEntity1 = PQLEntityFactory.newPQLEntity(queryTokens[0]);
_pqlOperator = PQLOperatorFactory.newPQLOperator(queryTokens[1]);
_pqlEntity2 = PQLEntityFactory.newPQLEntity(queryTokens[2]);
}
@Override
public Object getPQLResult(Properties properties) throws Exception {
Object pqlResultObject = _pqlOperator.getPQLResult(
_pqlEntity1, _pqlEntity2, properties);
if (!(pqlResultObject instanceof Boolean)) {
throw new Exception("Unable to evaluate " + getPQL());
}
PQLModifier pqlModifier = getPQLModifier();
if (pqlModifier != null) {
pqlResultObject = pqlModifier.getPQLResult(pqlResultObject);
}
return pqlResultObject;
}
private static List<String> _getAllTokens(String query) {
List<String> tokens = new ArrayList<>();
query = fixPQL(query);
while (true) {
if (query.startsWith("(") && query.contains(")")) {
int parenthesisCount = 0;
for (int i = 0; i < query.length(); i++) {
char c = query.charAt(i);
if (c == '(') {
parenthesisCount++;
}
if (c == ')') {
parenthesisCount--;
}
if (parenthesisCount < 0) {
return null;
}
if (parenthesisCount == 0) {
int x = i + 1;
String token = query.substring(0, x);
tokens.add(token.trim());
query = query.substring(x);
query = query.trim();
break;
}
}
if (parenthesisCount > 0) {
return null;
}
}
else if (_startsWithReservedToken(query)) {
String reservedToken = _getStartingReservedToken(query);
tokens.add(reservedToken);
query = query.substring(reservedToken.length());
query = query.trim();
}
else if (query.startsWith("\"") || query.startsWith("'")) {
int quotationTokenEndIndex = _getQuotationTokenEndIndex(query);
if (quotationTokenEndIndex == -1) {
return null;
}
String token = query.substring(0, quotationTokenEndIndex);
tokens.add(token.trim());
query = query.substring(quotationTokenEndIndex);
query = query.trim();
}
else if (query.contains(" ")) {
int x = query.indexOf(" ");
String token = query.substring(0, x);
tokens.add(token.trim());
query = query.substring(x);
query = query.trim();
}
else {
tokens.add(query.trim());
break;
}
}
return tokens;
}
private static String[] _getQueryTokens(String query) {
List<String> tokens = _getAllTokens(query);
if (tokens == null) {
return null;
}
List<List<String>> prioritizedOperatorList =
PQLOperator.getPrioritizedOperatorList();
int operatorIndex = -1;
for (int i = prioritizedOperatorList.size() - 1; i >= 0; i--) {
List<String> operators = prioritizedOperatorList.get(i);
for (int j = 0; j < tokens.size(); j++) {
String token = tokens.get(j);
if (operators.contains(token)) {
operatorIndex = j;
break;
}
}
if (operatorIndex != -1) {
break;
}
}
if (operatorIndex != -1) {
String entity1 = ListUtil.toString(
tokens.subList(0, operatorIndex), null, " ");
String operator = tokens.get(operatorIndex);
String entity2 = ListUtil.toString(
tokens.subList(operatorIndex + 1, tokens.size()), null, " ");
if (entity1.equals("") || entity2.equals("")) {
return null;
}
return new String[] {entity1, operator, entity2};
}
return null;
}
private static int _getQuotationTokenEndIndex(String query) {
boolean escapeNextChar = false;
char quotation = query.charAt(0);
for (int i = 1; i < query.length(); i++) {
char c = query.charAt(i);
if (escapeNextChar) {
escapeNextChar = false;
continue;
}
if (c == '\\') {
escapeNextChar = true;
continue;
}
if (c == quotation) {
return i + 1;
}
}
return -1;
}
private static String _getStartingReservedToken(String query) {
List<String> reservedTokens = new ArrayList<>();
reservedTokens.addAll(PQLOperator.getAvailableOperators());
for (String reservedToken : reservedTokens) {
if (query.equals(reservedToken) ||
query.startsWith(reservedToken + " ")) {
return reservedToken;
}
}
return null;
}
private static boolean _startsWithReservedToken(String query) {
String startingReservedToken = _getStartingReservedToken(query);
if (startingReservedToken != null) {
return true;
}
return false;
}
private void _validateQuery(String query) throws Exception {
if (!isQuery(query)) {
throw new Exception("Invalid query: " + query);
}
}
private final PQLEntity _pqlEntity1;
private final PQLEntity _pqlEntity2;
private final PQLOperator _pqlOperator;
}