/jira-project/jira-components/jira-core/src/main/java/com/atlassian/jira/jql/validator/ValidatorVisitor.java
Java | 197 lines | 152 code | 26 blank | 19 comment | 18 complexity | d15a728cb38c7e64616039d72355bc19 MD5 | raw file
Possible License(s): Apache-2.0
- package com.atlassian.jira.jql.validator;
- import com.atlassian.jira.issue.search.optimizers.DeterminedProjectsExtractor;
- import com.atlassian.jira.jql.operand.JqlOperandResolver;
- import com.atlassian.jira.jql.query.QueryCreationContext;
- import com.atlassian.jira.jql.query.QueryCreationContextImpl;
- import com.atlassian.jira.user.ApplicationUser;
- import com.atlassian.jira.util.I18nHelper;
- import com.atlassian.jira.util.ListOrderedMessageSetImpl;
- import com.atlassian.jira.util.MessageSet;
- import com.atlassian.jira.util.dbc.Assertions;
- import com.atlassian.jira.web.bean.I18nBean;
- import com.atlassian.query.clause.AndClause;
- import com.atlassian.query.clause.ChangedClause;
- import com.atlassian.query.clause.Clause;
- import com.atlassian.query.clause.ClauseVisitor;
- import com.atlassian.query.clause.NotClause;
- import com.atlassian.query.clause.OrClause;
- import com.atlassian.query.clause.TerminalClause;
- import com.atlassian.query.clause.WasClause;
- import com.atlassian.query.operand.Operand;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.List;
- import java.util.Set;
- /**
- * Used to perform validation over a {@link com.atlassian.query.Query}. Uses
- * {@link com.atlassian.jira.jql.validator.ClauseValidator}'s to validate the individual clauses and
- * {@link com.atlassian.jira.jql.operand.OperandHandler#validate(User, com.atlassian.query.operand.Operand, com.atlassian.query.clause.TerminalClause)}
- * to validate the operands.
- *
- * @since v4.0
- */
- public class ValidatorVisitor implements ClauseVisitor<MessageSet> {
- private final ValidatorRegistry validatorRegistry;
- private final JqlOperandResolver operandResolver;
- private final OperatorUsageValidator operatorUsageValidator;
- private final ApplicationUser searcher;
- private final Long filterId;
- private final Clause parentClause;
- public ValidatorVisitor(final ValidatorRegistry validatorRegistry, final JqlOperandResolver operandResolver,
- final OperatorUsageValidator operatorUsageValidator, final ApplicationUser searcher, final Long filterId, final Clause parentClause) {
- this.validatorRegistry = validatorRegistry;
- this.operandResolver = operandResolver;
- this.operatorUsageValidator = operatorUsageValidator;
- this.searcher = searcher;
- this.filterId = filterId;
- this.parentClause = parentClause;
- }
- public MessageSet visit(final AndClause andClause) {
- return getMessagesFromSubClauses(andClause.getClauses(), andClause);
- }
- public MessageSet visit(final NotClause notClause) {
- return getMessagesFromSubClauses(Collections.singletonList(notClause.getSubClause()), notClause);
- }
- public MessageSet visit(final OrClause orClause) {
- return getMessagesFromSubClauses(orClause.getClauses(), orClause);
- }
- public MessageSet visit(final TerminalClause clause) {
- final Collection<ClauseValidator> validators = validatorRegistry.getClauseValidator(searcher, clause);
- final MessageSet messages = validateOperatorAndOperand(clause, validators);
- if (messages.hasAnyErrors()) {
- return messages;
- }
- // Now validate the clause itself
- validateClause(clause, validators, messages);
- return messages;
- }
- private MessageSet validateOperatorAndOperand(TerminalClause clause, Collection<ClauseValidator> validators) {
- final MessageSet messages = new ListOrderedMessageSetImpl();
- // JRA-18554 It does not make sense to validate the operands or operators if the clause does not exist
- if (!validators.isEmpty()) {
- // Validate the operator makes sense from a global perspective
- if (validateOperator(clause, messages)) {
- // Short-circuit if there are any errors, we are cool if there are warnings
- return messages;
- }
- // Validate the terminal clauses operands
- if (validateOperands(clause, messages)) {
- // Short-circuit if there are any errors, we are cool if there are warnings
- return messages;
- }
- }
- return messages;
- }
- @Override
- public MessageSet visit(WasClause clause) {
- final Collection<ClauseValidator> wasClauseValidators = validatorRegistry.getClauseValidator(searcher, clause);
- final MessageSet messages = validateOperatorAndOperand(clause, wasClauseValidators);
- if (messages.hasAnyMessages()) {
- return messages;
- }
- // Now validate the clause itself
- validateClause(clause, wasClauseValidators, messages);
- return messages;
- }
- @Override
- public MessageSet visit(ChangedClause clause) {
- final ChangedClauseValidator changedClauseValidator = validatorRegistry.getClauseValidator(searcher, clause);
- return changedClauseValidator.validate(searcher, clause);
- }
- private boolean validateOperator(final TerminalClause clause, final MessageSet messages) {
- messages.addMessageSet(operatorUsageValidator.validate(searcher, clause));
- return messages.hasAnyErrors();
- }
- private void validateClause(final TerminalClause clause, final Collection<ClauseValidator> validators, final MessageSet messages) {
- if (!validators.isEmpty()) {
- for (ClauseValidator validator : validators) {
- final MessageSet messageSet;
- if (validator instanceof SavedFilterClauseValidator) {
- messageSet = ((SavedFilterClauseValidator) validator).validate(searcher, clause, filterId);
- } else if (validator instanceof AbstractVersionValidator) {
- final DeterminedProjectsExtractor determinedProjectsExtractor = new DeterminedProjectsExtractor();
- final Set<String> determinedProjects = determinedProjectsExtractor.extractDeterminedProjectsFromClause(parentClause);
- final QueryCreationContext contextWithClause = new QueryCreationContextImpl(searcher, false, determinedProjects);
- messageSet = ((AbstractVersionValidator) validator).validate(clause, contextWithClause);
- } else {
- messageSet = validator.validate(searcher, clause);
- }
- messages.addMessageSet(messageSet);
- }
- } else {
- I18nHelper i18n = getI18n();
- //JRADEV-2649: Provide slighly more feedback about logged in/logged out state, so that clients can
- //display more useful error messages
- if (searcher != null) {
- messages.addErrorMessage(i18n.getText("jira.jql.validation.no.such.field", clause.getName()));
- } else {
- messages.addErrorMessage(i18n.getText("jira.jql.validation.no.such.field.anonymous", clause.getName()));
- }
- }
- }
- ///CLOVER:OFF
- I18nHelper getI18n() {
- return new I18nBean(searcher);
- }
- ///CLOVER:ON
- private boolean validateOperands(final TerminalClause clause, final MessageSet messages) {
- final Operand operand = clause.getOperand();
- messages.addMessageSet(operandResolver.validate(searcher, operand, clause));
- return messages.hasAnyErrors();
- }
- private MessageSet getMessagesFromSubClauses(List<Clause> subClauses, Clause parentClause) {
- final MessageSet messages = new ListOrderedMessageSetImpl();
- for (Clause subClause : subClauses) {
- final MessageSet subMessages = subClause.accept(createNewVisitor(parentClause));
- if (subMessages != null) {
- messages.addMessageSet(subMessages);
- }
- }
- return messages;
- }
- private ValidatorVisitor createNewVisitor(final Clause parentClause) {
- return new ValidatorVisitor(validatorRegistry, operandResolver, operatorUsageValidator, searcher, filterId, parentClause);
- }
- public static class ValidatorVisitorFactory {
- private final ValidatorRegistry validatorRegistry;
- private final JqlOperandResolver operandResolver;
- private final OperatorUsageValidator operatorUsageValidator;
- public ValidatorVisitorFactory(final ValidatorRegistry validatorRegistry, final JqlOperandResolver operandResolver, final OperatorUsageValidator operatorUsageValidator) {
- this.validatorRegistry = Assertions.notNull("validatorRegistry", validatorRegistry);
- this.operandResolver = Assertions.notNull("operandResolver", operandResolver);
- this.operatorUsageValidator = Assertions.notNull("operatorUsageValidator", operatorUsageValidator);
- }
- public ValidatorVisitor createVisitor(ApplicationUser searcher, Long filterId) {
- return new ValidatorVisitor(validatorRegistry, operandResolver, operatorUsageValidator, searcher, filterId, null);
- }
- public ValidatorVisitor createVisitor(ApplicationUser searcher, Long filterId, Clause parentClause) {
- return new ValidatorVisitor(validatorRegistry, operandResolver, operatorUsageValidator, searcher, filterId, parentClause);
- }
- }
- }