package org.ovirt.engine.core.searchbackend; import org.ovirt.engine.core.compat.Regex; import org.ovirt.engine.core.compat.StringBuilderCompat; import org.ovirt.engine.core.compat.StringFormat; import org.ovirt.engine.core.compat.StringHelper; public class ADSyntaxChecker implements ISyntaxChecker { private AdSearchObjecAutoCompleter mSearchObjectAC; private BaseAutoCompleter mColonAC; private BaseAutoCompleter mPluralAC; private java.util.HashMap<SyntaxObjectType, SyntaxObjectType[]> mStateMap; protected final static String USER_ACCOUNT_TYPE = "$USER_ACCOUNT_TYPE"; private final static String LDAP_GROUP_CATEGORY = "$LDAP_GROUP_CATEGORY"; private Regex mFirstDQRegexp; private Regex mNonSpaceRegexp; public ADSyntaxChecker() { mSearchObjectAC = new AdSearchObjecAutoCompleter(); mColonAC = new BaseAutoCompleter(":"); mPluralAC = new BaseAutoCompleter("S"); mFirstDQRegexp = new Regex("^\\s*\"$"); mNonSpaceRegexp = new Regex("^\\S+$"); mStateMap = new java.util.HashMap<SyntaxObjectType, SyntaxObjectType[]>(); SyntaxObjectType[] beginArray = { SyntaxObjectType.SEARCH_OBJECT }; mStateMap.put(SyntaxObjectType.BEGIN, beginArray); SyntaxObjectType[] searchObjectArray = { SyntaxObjectType.COLON }; mStateMap.put(SyntaxObjectType.SEARCH_OBJECT, searchObjectArray); SyntaxObjectType[] colonArray = { SyntaxObjectType.CONDITION_FIELD, SyntaxObjectType.END }; mStateMap.put(SyntaxObjectType.COLON, colonArray); SyntaxObjectType[] conditionFieldArray = { SyntaxObjectType.CONDITION_RELATION }; mStateMap.put(SyntaxObjectType.CONDITION_FIELD, conditionFieldArray); SyntaxObjectType[] conditionRelationArray = { SyntaxObjectType.CONDITION_VALUE }; mStateMap.put(SyntaxObjectType.CONDITION_RELATION, conditionRelationArray); SyntaxObjectType[] conditionValueArray = { SyntaxObjectType.CONDITION_FIELD }; mStateMap.put(SyntaxObjectType.CONDITION_VALUE, conditionValueArray); } public SyntaxContainer analyzeSyntaxState(String searchText, boolean final2) { SyntaxContainer retval = new SyntaxContainer(searchText); IConditionFieldAutoCompleter AdConditionFieldAC; if (searchText.toUpperCase().contains("ADUSER")) { AdConditionFieldAC = new AdUserConditionFieldAutoCompleter(); } else { AdConditionFieldAC = new AdGroupConditionFieldAutoCompleter(); } IAutoCompleter conditionRelationAC; char[] searchCharArr = searchText.toCharArray(); boolean betweenDoubleQuotes = false; int curStartPos = 0; String curConditionField = ""; for (int idx = 0; idx < searchCharArr.length; idx++) { SyntaxObjectType curState = retval.getState(); char curChar = searchCharArr[idx]; if ((curChar == ' ') && (curState != SyntaxObjectType.CONDITION_RELATION)) { curStartPos += 1; continue; } String strRealObj = searchText.substring(curStartPos, idx + 1); String nextObject = strRealObj.toUpperCase(); switch (curState) { case BEGIN: // we have found a search-object if (!mSearchObjectAC.validate(nextObject)) { if (!mSearchObjectAC.validateCompletion(nextObject)) { // ERROR INVALID-SEARCH OBJECT retval.setErr(SyntaxError.INVALID_SEARCH_OBJECT, curStartPos, idx - curStartPos + 1); return retval; } } else { if (searchCharArr.length >= idx + 2) // Check that this // maybe a plural { // Validate that the next character is an 's' if (mPluralAC.validate(searchText.substring(idx + 1, idx + 1 + 1))) { // Then just move things along. idx++; StringBuilderCompat sb = new StringBuilderCompat(nextObject); sb.append('S'); nextObject = sb.toString(); } } retval.addSyntaxObject(SyntaxObjectType.SEARCH_OBJECT, nextObject, curStartPos, idx + 1); retval.setvalid(true); curStartPos = idx + 1; } break; case SEARCH_OBJECT: if (!mColonAC.validate(nextObject)) { if (!mColonAC.validateCompletion(nextObject)) { retval.setErr(SyntaxError.COLON_NOT_NEXT_TO_SEARCH_OBJECT, curStartPos, idx + 1); return retval; } } else { retval.addSyntaxObject(SyntaxObjectType.COLON, nextObject, idx, idx + 1); curStartPos = idx + 1; retval.setvalid(true); } break; case COLON: case CONDITION_VALUE: if (AdConditionFieldAC.validate(nextObject)) { retval.addSyntaxObject(SyntaxObjectType.CONDITION_FIELD, nextObject, curStartPos, idx + 1); curConditionField = nextObject; curStartPos = idx + 1; } else if (!AdConditionFieldAC.validateCompletion(nextObject)) // && // (!mSortbyAC.validateCompletion(nextObject))) { retval.setErr(SyntaxError.INVALID_CONDITION_FILED, curStartPos, idx + 1); return retval; } retval.setvalid(false); break; case CONDITION_FIELD: conditionRelationAC = AdConditionFieldAC.getFieldRelationshipAutoCompleter(curConditionField); if (conditionRelationAC == null) { retval.setErr(SyntaxError.CONDITION_CANT_CREATE_RRELATIONS_AC, curStartPos, idx + 1); return retval; } if (idx + 1 < searchCharArr.length) { String tryNextObj = searchText.substring(curStartPos, idx + 2).toUpperCase(); if (conditionRelationAC.validate(tryNextObj)) { break; } } if (!conditionRelationAC.validate(nextObject)) { if (!conditionRelationAC.validateCompletion(nextObject)) { retval.setErr(SyntaxError.INVALID_CONDITION_RELATION, curStartPos, idx + 1); return retval; } } else { retval.addSyntaxObject(SyntaxObjectType.CONDITION_RELATION, nextObject, curStartPos, idx + 1); } curStartPos = idx + 1; retval.setvalid(false); break; case CONDITION_RELATION: boolean addObjFlag = false; if (curChar == '"') { betweenDoubleQuotes = (!betweenDoubleQuotes); if (betweenDoubleQuotes) { if (!mFirstDQRegexp.IsMatch(strRealObj)) { retval.setErr(SyntaxError.INVALID_CONDITION_VALUE, curStartPos, idx + 1); return retval; } } else { strRealObj = StringHelper.trim(strRealObj, new char[] { '\"' }); addObjFlag = true; } } // Doing this condition to identify whether this is the last // searchObject and no space is predicted !! if (final2) { if (((curChar == ' ') || (idx + 1 == searchCharArr.length)) && (betweenDoubleQuotes == false) && (addObjFlag == false)) { strRealObj = strRealObj.trim(); if (mNonSpaceRegexp.IsMatch(strRealObj)) { addObjFlag = true; } else { curStartPos = idx + 1; } } } else { if ((curChar == ' ') && (betweenDoubleQuotes == false) && (addObjFlag == false)) { strRealObj = strRealObj.trim(); if (mNonSpaceRegexp.IsMatch(strRealObj)) { addObjFlag = true; } else { curStartPos = idx + 1; } } } if (addObjFlag) { if (!AdConditionFieldAC.validateFieldValue(curConditionField, strRealObj)) { retval.setErr(SyntaxError.INVALID_CONDITION_VALUE, curStartPos, idx); return retval; } else { retval.addSyntaxObject(SyntaxObjectType.CONDITION_VALUE, strRealObj, curStartPos, idx + 1); curConditionField = ""; } curStartPos = idx + 1; retval.setvalid(true); } break; default: retval.setErr(SyntaxError.UNIDENTIFIED_STATE, curStartPos, idx); return retval; } } return retval; } public SyntaxContainer getCompletion(String searchText) { SyntaxContainer retval = analyzeSyntaxState(searchText, false); IConditionFieldAutoCompleter AdConditionFieldAC; if (retval.getError() == SyntaxError.NO_ERROR) { if (searchText.toUpperCase().contains("ADUSER")) { AdConditionFieldAC = new AdUserConditionFieldAutoCompleter(); } else { AdConditionFieldAC = new AdGroupConditionFieldAutoCompleter(); } IAutoCompleter conditionRelationAC; IConditionValueAutoCompleter conditionValueAC; int lastIdx = retval.getLastHandledIndex(); String curPartialWord = ""; if (lastIdx < searchText.length()) { curPartialWord = searchText.substring(lastIdx, searchText.length()); curPartialWord = curPartialWord.trim(); } SyntaxObjectType curState = retval.getState(); for (int idx = 0; idx < mStateMap.get(curState).length; idx++) { switch (mStateMap.get(curState)[idx]) { case SEARCH_OBJECT: retval.addToACList(mSearchObjectAC.getCompletion(curPartialWord)); break; case COLON: retval.addToACList(mColonAC.getCompletion(curPartialWord)); break; case CONDITION_FIELD: String[] tmpCompletions = AdConditionFieldAC.getCompletion(curPartialWord); java.util.ArrayList<String> nonDuplicates = new java.util.ArrayList<String>(); for (int itr = 0; itr < tmpCompletions.length; itr++) { if (!retval.contains(SyntaxObjectType.CONDITION_FIELD, tmpCompletions[itr])) { nonDuplicates.add(tmpCompletions[itr]); } } retval.addToACList(nonDuplicates.toArray(new String[] {})); break; case CONDITION_RELATION: conditionRelationAC = AdConditionFieldAC.getFieldRelationshipAutoCompleter(retval .getPreviousSyntaxObject(1, SyntaxObjectType.CONDITION_FIELD)); if (conditionRelationAC != null) { retval.addToACList(conditionRelationAC.getCompletion(curPartialWord)); } break; case CONDITION_VALUE: conditionValueAC = AdConditionFieldAC.getFieldValueAutoCompleter(retval.getPreviousSyntaxObject(2, SyntaxObjectType.CONDITION_FIELD)); if (conditionValueAC != null) { retval.addToACList(conditionValueAC.getCompletion(curPartialWord)); } break; } } } return retval; } public String generateQueryFromSyntaxContainer(SyntaxContainer syntax, boolean isSafe) { String retval = ""; if (syntax.getvalid()) { retval = generateAdQueryFromSyntaxContainer(syntax); } return retval; } private static String generateAdQueryFromSyntaxContainer(SyntaxContainer syntax) { StringBuilderCompat retval = new StringBuilderCompat(); if (syntax.getvalid()) { IConditionFieldAutoCompleter conditionFieldAC; if (syntax.getSearchObjectStr().toUpperCase().contains("ADUSER")) { retval.append("(&"); retval.append("(" + USER_ACCOUNT_TYPE + ")"); conditionFieldAC = new AdUserConditionFieldAutoCompleter(); } else { retval.append("(&(" + LDAP_GROUP_CATEGORY + ")"); conditionFieldAC = new AdGroupConditionFieldAutoCompleter(); } StringBuilderCompat phrase = new StringBuilderCompat(); boolean nonEqual = false; boolean findAll = false; for (SyntaxObject so : syntax) { switch (so.getType()) { case CONDITION_FIELD: if (StringHelper.EqOp(so.getBody(), "ALLNAMES")) { phrase.append(" (|($GIVENNAME={value})(sn={value})($USER_ACCOUNT_NAME={value})($PRINCIPAL_NAME={value}))"); /** * mark this search as findAll for later use */ findAll = true; } else { phrase.append(StringFormat.format(" (%1$s", conditionFieldAC.getDbFieldName(so.getBody()))); } break; case CONDITION_RELATION: /** * append '=' only if not finding all */ if (!findAll) { phrase.append("="); } if (StringHelper.EqOp(so.getBody(), "!=")) { nonEqual = true; } break; case CONDITION_VALUE: if (findAll) { /** * replace all {value} occurences with the value searched. We escape the $ here for regex match, * as it is used in replace. */ phrase.replace("{value}", so.getBody().replace("$", "\\$")); } else { phrase.append(StringFormat.format("%1$s)", so.getBody())); } if (nonEqual) { retval.append(StringFormat.format("(!%1$s)", phrase)); } else { retval.append(phrase.toString()); } nonEqual = false; findAll = false; phrase.delete(0, phrase.length()); break; default: break; } } } retval.append(")"); return retval.toString(); } }