blob: 39182bb420c45e65d5b396871d427470f36065a3 [file] [log] [blame]
/*
* Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation
//
package org.eclipse.persistence.jpa.jpql.tools.model.query;
import java.io.IOException;
import java.util.List;
import org.eclipse.persistence.jpa.jpql.parser.CaseExpression;
import org.eclipse.persistence.jpa.jpql.parser.CaseOperandBNF;
import org.eclipse.persistence.jpa.jpql.parser.ElseExpressionBNF;
import org.eclipse.persistence.jpa.jpql.tools.model.Problem;
import static org.eclipse.persistence.jpa.jpql.parser.AbstractExpression.*;
/**
* A <code><b>CASE</b></code> predicate is used to calculate a condition and when it's <code>true</code>,
* its <code><b>THEN</b></code> expression will be executed.
*
* <div><b>BNF:</b> <code>general_case_expression ::= CASE when_clause {when_clause}* ELSE scalar_expression END</code></div>
* or
* <div><p><b>BNF:</b> <code>simple_case_expression ::= CASE case_operand simple_when_clause {simple_when_clause}* ELSE scalar_expression END</code></p></div>
*
* @see WhenClauseStateObject
* @see org.eclipse.persistence.jpa.jpql.parser.CaseExpression CaseExpression
*
* @version 2.4
* @since 2.4
* @author Pascal Filion
*/
@SuppressWarnings({"nls", "unused"}) // unused used for the import statement: see bug 330740
public class CaseExpressionStateObject extends AbstractListHolderStateObject<WhenClauseStateObject> {
/**
* The {@link StateObject} representing the case operand that is following the <code><b>CASE</b></code>
* identifier.
*/
private StateObject caseOperandStateObject;
/**
* The {@link StateObject} representing the scalar expression that is following the <code><b>ELSE</b></code>
* identifier.
*/
private StateObject elseStateObject;
/**
* Notify the {@link StateObject} representing the case operand that follows the
* <code><b>CASE</b></code> identifier has changed.
*/
public static final String CASE_OPERAND_STATE_OBJECT_PROPERTY = "caseOperandStateObject";
/**
* Notify the {@link StateObject} representing the else expression that follows the
* <code><b>ELSE</b></code> identifier has changed.
*/
public static final String ELSE_STATE_OBJECT_PROPERTY = "elseStateObject";
/**
* Notify the list of {@link StateObject StateObjects} representing the when clauses that
* follow the <code><b>WHEN</b></code> has changed.
*/
public static final String WHEN_CLAUSE_STATE_OBJECT_LIST = "whenStateObjects";
/**
* Creates a new <code>CaseExpressionStateObject</code>.
*
* @param parent The parent of this state object, which cannot be <code>null</code>
* @exception NullPointerException The given parent cannot be <code>null</code>
*/
public CaseExpressionStateObject(StateObject parent) {
super(parent);
}
/**
* Creates a new <code>CaseExpressionStateObject</code>.
*
* @param parent The parent of this state object, which cannot be <code>null</code>
* @param whenClauseStateObjects The list of {@link WhenClauseStateObject WhenClauseStateObjects}
* that are representing the <code><b>WHEN</b></code> clauses
* @param elseStateObject The {@link StateObject} representing the scalar expression that is
* following the <code><b>ELSE</b></code> identifier
* @exception NullPointerException The given parent cannot be <code>null</code>
*/
public CaseExpressionStateObject(StateObject parent,
List<WhenClauseStateObject> whenClauseStateObjects,
StateObject elseStateObject) {
this(parent, null, whenClauseStateObjects, elseStateObject);
}
/**
* Creates a new <code>CaseExpressionStateObject</code>.
*
* @param parent The parent of this state object, which cannot be <code>null</code>
* @param caseOperandStateObject The {@link StateObject} representing the case operand that is
* following the <code><b>CASE</b></code> identifier or <code>null</code> if none is declared
* @param whenClauseStateObjects The list of {@link WhenClauseStateObject WhenClauseStateObjects}
* that are representing the <code><b>WHEN</b></code> clauses
* @param elseStateObject The {@link StateObject} representing the scalar expression that is
* following the <code><b>ELSE</b></code> identifier
* @exception NullPointerException The given parent cannot be <code>null</code>
*/
public CaseExpressionStateObject(StateObject parent,
StateObject caseOperandStateObject,
List<WhenClauseStateObject> whenClauseStateObjects,
StateObject elseStateObject) {
super(parent, whenClauseStateObjects);
this.elseStateObject = parent(elseStateObject);
this.caseOperandStateObject = parent(caseOperandStateObject);
}
@Override
public void accept(StateObjectVisitor visitor) {
visitor.visit(this);
}
@Override
protected void addChildren(List<StateObject> children) {
if (caseOperandStateObject != null) {
children.add(caseOperandStateObject);
}
super.addChildren(children);
if (elseStateObject != null) {
children.add(elseStateObject);
}
}
@Override
protected void addProblems(List<Problem> problems) {
super.addProblems(problems);
// No validation required
}
/**
* Adds a new <code>WHEN</code> clause.
*
* @return The newly created {@link WhenClauseStateObject}
*/
public WhenClauseStateObject addWhenClause() {
WhenClauseStateObject whenClause = new WhenClauseStateObject(this);
addItem(whenClause);
return whenClause;
}
/**
* Adds the given two {@link StateObject StateObjects} as the <code>WHEN</code> expression and
* the <code>THEN</code> expression of the new <code>WHEN</code> clause.
*
* @param whenStateObject The {@link StateObject} representing the <code><b>WHEN</b></code>
* expression
* @param thenStateObject The {@link StateObject} representing the <code><b>THEN</b></code>
* expression
* @return The newly created {@link WhenClauseStateObject}
*/
public WhenClauseStateObject addWhenClause(StateObject whenStateObject,
StateObject thenStateObject) {
WhenClauseStateObject whenClause = new WhenClauseStateObject(
this,
whenStateObject,
thenStateObject
);
addItem(whenClause);
return whenClause;
}
/**
* Adds the given two {@link StateObject StateObjects} as the <code>WHEN</code> expression and
* the <code>THEN</code> expression of the new <code>WHEN</code> clause.
*
* @param whenJpqlFragment The string representation of the <code><b>WHEN</b></code> to parse and
* to convert into a {@link StateObject} representation
* @param thenJpqlFragment The string representation of the <code><b>THEN</b></code> to parse and
* to convert into a {@link StateObject} representation
* @return The newly created {@link WhenClauseStateObject}
*/
public WhenClauseStateObject addWhenClause(String whenJpqlFragment, String thenJpqlFragment) {
WhenClauseStateObject whenClause = new WhenClauseStateObject(this);
whenClause.parseWhen(whenJpqlFragment);
whenClause.parseThen(thenJpqlFragment);
addItem(whenClause);
return whenClause;
}
/**
* Returns the {@link StateObject} representing the case operand.
*
* @return The {@link StateObject} representing the case operand or <code>null</code> if it is
* not present
*/
public StateObject getCaseOperand() {
return caseOperandStateObject;
}
/**
* Returns the {@link StateObject} representing the <code><b>ELSE</b></code> scalar expression.
*
* @return The {@link StateObject} representing the <code><b>ELSE</b></code> scalar expression
* or <code>null</code> if it is not present
*/
public StateObject getElse() {
return elseStateObject;
}
@Override
public CaseExpression getExpression() {
return (CaseExpression) super.getExpression();
}
/**
* Determines whether the {@link StateObject} representing the case operand is present.
*
* @return <code>true</code> the case operand exists; otherwise <code>false</code>
*/
public boolean hasCaseOperand() {
return caseOperandStateObject != null;
}
/**
* Determines whether the {@link StateObject} representing the <code><b>ELSE</b></code> scalar
* expression is present.
*
* @return <code>true</code> the <code><b>ELSE</b></code> scalar expression exists; otherwise
* <code>false</code>
*/
public boolean hasElse() {
return elseStateObject != null;
}
@Override
public boolean isEquivalent(StateObject stateObject) {
if (super.isEquivalent(stateObject)) {
CaseExpressionStateObject caseExpression = (CaseExpressionStateObject) stateObject;
return areEquivalent(elseStateObject, caseExpression.elseStateObject) &&
areEquivalent(caseOperandStateObject, caseExpression.caseOperandStateObject) &&
areChildrenEquivalent(caseExpression);
}
return false;
}
@Override
protected String listName() {
return WHEN_CLAUSE_STATE_OBJECT_LIST;
}
/**
* Parses the given JPQL fragment, which will represent the case operand. The JPQL fragment should
* not start with the identifier.
*
* @param jpqlFragment The string representation of the case operand to parse and to convert into
* a {@link StateObject} representation
*/
public void parseCaseOperand(String jpqlFragment) {
StateObject stateObject = buildStateObject(jpqlFragment, CaseOperandBNF.ID);
setCaseOperand(stateObject);
}
/**
* Parses the given JPQL fragment, which will represent the <code><b>ELSE</b></code> expression.
* The JPQL fragment should not start with the identifier.
*
* @param jpqlFragment The string representation of the <code><b>ELSE</b></code> to parse and to
* convert into a {@link StateObject} representation
*/
public void parseElse(String jpqlFragment) {
StateObject stateObject = buildStateObject(jpqlFragment, ElseExpressionBNF.ID);
setElse(stateObject);
}
/**
* Removes the case operand.
*/
public void removeCaseOperand() {
setCaseOperand(null);
}
/**
* Sets the case operand to be the given {@link StateObject}.
*
* @param caseOperand The {@link StateObject} representing the case operand or
* <code>null</code> to remove it
*/
public void setCaseOperand(StateObject caseOperand) {
StateObject oldCaseOperandStateObject = this.caseOperandStateObject;
this.caseOperandStateObject = parent(caseOperand);
firePropertyChanged(CASE_OPERAND_STATE_OBJECT_PROPERTY, oldCaseOperandStateObject, caseOperand);
}
/**
* Sets the <code><b>ELSE</b></code> scalar expression to be the given {@link StateObject}.
*
* @param elseStateObject The {@link StateObject} representing the <code><b>ELSE</b></code>
* scalar expression or <code>null</code> to remove it
*/
public void setElse(StateObject elseStateObject) {
StateObject oldElseStateObject = this.elseStateObject;
this.elseStateObject = parent(elseStateObject);
firePropertyChanged(ELSE_STATE_OBJECT_PROPERTY, oldElseStateObject, elseStateObject);
}
/**
* Keeps a reference of the {@link CaseExpression parsed object} object, which should only be
* done when this object is instantiated during the conversion of a parsed JPQL query into
* {@link StateObject StateObjects}.
*
* @param expression The {@link CaseExpression parsed object} representing a <code><b>CASE</b></code>
* expression
*/
public void setExpression(CaseExpression expression) {
super.setExpression(expression);
}
@Override
public void toTextInternal(Appendable writer) throws IOException {
// CASE
writer.append(CASE);
writer.append(SPACE);
// Case operand
if (hasCaseOperand()) {
caseOperandStateObject.toString(writer);
writer.append(SPACE);
}
// WHEN clauses
if (hasItems()) {
toStringItems(writer, false);
writer.append(SPACE);
}
// ELSE scalar expression
writer.append(ELSE);
writer.append(SPACE);
if (hasElse()) {
elseStateObject.toString(writer);
writer.append(SPACE);
}
// END
writer.append(END);
}
}