blob: fe673cda5989fde82336ef7dd85135f11cde288b [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.AbstractTripleEncapsulatedExpression;
import static org.eclipse.persistence.jpa.jpql.parser.AbstractExpression.*;
/**
* This state object takes care of parsing an expression that encapsulates three expressions
* separated by a comma.
*
* <div><p><b>BNF:</b> <code>expression ::= &lt;identifier&gt;(first_expression, second_expression, third_expression)</code></p></div>
*
* @see LocateExpressionStateObject
* @see SubstringExpressionStateObject
*
* @see AbstractTripleEncapsulatedExpression
*
* @version 2.4
* @since 2.4
* @author Pascal Filion
*/
@SuppressWarnings("nls")
public abstract class AbstractTripleEncapsulatedExpressionStateObject extends AbstractEncapsulatedExpressionStateObject {
/**
* The {@link StateObject} representing the first expression.
*/
private StateObject firstStateObject;
/**
* The {@link StateObject} representing the second expression.
*/
private StateObject secondStateObject;
/**
* The {@link StateObject} representing the third expression.
*/
private StateObject thirdStateObject;
/**
* Notifies the first {@link StateObject} property has changed.
*/
public static final String FIRST_STATE_OBJECT_PROPERTY = "firstStateObject";
/**
* Notifies the second {@link StateObject} property has changed.
*/
public static final String SECOND_STATE_OBJECT_PROPERTY = "secondStateObject";
/**
* Notifies the third {@link StateObject} property has changed.
*/
public static final String THIRD_STATE_OBJECT_PROPERTY = "thirdStateObject";
/**
* Creates a new <code>AbstractTripleEncapsulatedExpressionStateObject</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>
*/
protected AbstractTripleEncapsulatedExpressionStateObject(StateObject parent) {
super(parent);
}
/**
* Creates a new <code>AbstractTripleEncapsulatedExpressionStateObject</code>.
*
* @param parent The parent of this state object, which cannot be <code>null</code>
* @param firstStateObject The {@link StateObject} of the first encapsulated expression
* @param secondStateObject The {@link StateObject} of the second encapsulated expression
* @param thirdStateObject The {@link StateObject} of the third encapsulated expression
* @exception NullPointerException The given parent cannot be <code>null</code>
*/
protected AbstractTripleEncapsulatedExpressionStateObject(StateObject parent,
StateObject firstStateObject,
StateObject secondStateObject,
StateObject thirdStateObject) {
super(parent);
this.firstStateObject = parent(firstStateObject);
this.secondStateObject = parent(secondStateObject);
this.thirdStateObject = parent(thirdStateObject);
}
/**
* Creates a new <code>AbstractTripleEncapsulatedExpressionStateObject</code>.
*
* @param parent The parent of this state object, which cannot be <code>null</code>
* @param firstJpqlFragment The string representation of the first encapsulated expression to
* parse and to convert into a {@link StateObject} representation
* @param secondJpqlFragment The string representation of the second encapsulated expression to
* parse and to convert into a {@link StateObject} representation
* @param thirdJpqlFragment The string representation of the third encapsulated expression to
* parse and to convert into a {@link StateObject} representation
* @exception NullPointerException The given parent cannot be <code>null</code>
*/
protected AbstractTripleEncapsulatedExpressionStateObject(StateObject parent,
String firstJpqlFragment,
String secondJpqlFragment,
String thirdJpqlFragment) {
super(parent);
parseFirst (firstJpqlFragment);
parseSecond(secondJpqlFragment);
parseThird (thirdJpqlFragment);
}
@Override
protected void addChildren(List<StateObject> children) {
super.addChildren(children);
if (firstStateObject != null) {
children.add(firstStateObject);
}
if (secondStateObject != null) {
children.add(secondStateObject);
}
if (thirdStateObject != null) {
children.add(thirdStateObject);
}
}
@Override
public AbstractTripleEncapsulatedExpression getExpression() {
return (AbstractTripleEncapsulatedExpression) super.getExpression();
}
/**
* Returns the {@link StateObject} representing the first expression.
*
* @return The first encapsulated {@link StateObject} or <code>null</code> if none exists
*/
public StateObject getFirst() {
return firstStateObject;
}
/**
* Returns the unique identifier of the BNF that will be used to parse a JPQL fragment as the
* first encapsulated expression.
*
* @return The query BNF ID for the first encapsulated expression
*/
protected abstract String getFirstQueryBNFId();
/**
* Returns the {@link StateObject} representing the second expression.
*
* @return The second encapsulated {@link StateObject} or <code>null</code> if none exists
*/
public StateObject getSecond() {
return secondStateObject;
}
/**
* Returns the unique identifier of the BNF that will be used to parse a JPQL fragment as the
* second encapsulated expression.
*
* @return The query BNF ID for the second encapsulated expression
*/
protected abstract String getSecondQueryBNFId();
/**
* Returns the {@link StateObject} representing the third expression.
*
* @return The third encapsulated {@link StateObject} or <code>null</code> if none exists
*/
public StateObject getThird() {
return thirdStateObject;
}
/**
* Returns the unique identifier of the BNF that will be used to parse a JPQL fragment as the
* third encapsulated expression.
*
* @return The query BNF ID for the third encapsulated expression
*/
protected abstract String getThirdQueryBNFId();
/**
* Determines whether the {@link StateObject} representing the first encapsulated expression is
* present or not.
*
* @return <code>true</code> if the first {@link StateObject} is not <code>null</code>;
* <code>false</code> otherwise
*/
public boolean hasFirst() {
return firstStateObject != null;
}
/**
* Determines whether the {@link StateObject} representing the second encapsulated expression is
* present or not.
*
* @return <code>true</code> if the second {@link StateObject} is not <code>null</code>;
* <code>false</code> otherwise
*/
public boolean hasSecond() {
return secondStateObject != null;
}
/**
* Determines whether the {@link StateObject} representing the third encapsulated expression is
* present or not.
*
* @return <code>true</code> if the third {@link StateObject} is not <code>null</code>;
* <code>false</code> otherwise
*/
public boolean hasThird() {
return thirdStateObject != null;
}
@Override
public boolean isEquivalent(StateObject stateObject) {
if (super.isEquivalent(stateObject)) {
AbstractTripleEncapsulatedExpressionStateObject encapsulated = (AbstractTripleEncapsulatedExpressionStateObject) stateObject;
return areEquivalent(firstStateObject, encapsulated.firstStateObject) &&
areEquivalent(secondStateObject, encapsulated.secondStateObject) &&
areEquivalent(thirdStateObject, encapsulated.thirdStateObject);
}
return false;
}
/**
* Parses the given JPQL fragment, which will represent the first encapsulated expression.
*
* @param jpqlFragment The string representation of the first encapsulated expression to parse and
* to convert into a {@link StateObject} representation
*/
public void parseFirst(String jpqlFragment) {
StateObject stateObject = buildStateObject(jpqlFragment, getFirstQueryBNFId());
setFirst(stateObject);
}
/**
* Parses the given JPQL fragment, which will represent the second encapsulated expression.
*
* @param jpqlFragment The string representation of the second encapsulated expression to parse and
* to convert into a {@link StateObject} representation
*/
public void parseSecond(String jpqlFragment) {
StateObject stateObject = buildStateObject(jpqlFragment, getSecondQueryBNFId());
setSecond(stateObject);
}
/**
* Parses the given JPQL fragment, which will represent the third encapsulated expression.
*
* @param jpqlFragment The string representation of the third encapsulated expression to parse and
* to convert into a {@link StateObject} representation
*/
public void parseThird(String jpqlFragment) {
StateObject stateObject = buildStateObject(jpqlFragment, getThirdQueryBNFId());
setThird(stateObject);
}
/**
* Sets the given {@link StateObject} to represent the first encapsulated expression.
*
* @param firstStateObject The new encapsulated {@link StateObject} representing the first
* expression
*/
public void setFirst(StateObject firstStateObject) {
StateObject oldFirstStateObject = this.firstStateObject;
this.firstStateObject = parent(firstStateObject);
firePropertyChanged(FIRST_STATE_OBJECT_PROPERTY, oldFirstStateObject, firstStateObject);
}
/**
* Sets the given {@link StateObject} to represent the second encapsulated expression.
*
* @param secondStateObject The new encapsulated {@link StateObject} representing the second
* expression
*/
public void setSecond(StateObject secondStateObject) {
StateObject oldSecondStateObject = this.firstStateObject;
this.secondStateObject = parent(secondStateObject);
firePropertyChanged(SECOND_STATE_OBJECT_PROPERTY, oldSecondStateObject, secondStateObject);
}
/**
* Sets the given {@link StateObject} to represent the third encapsulated expression.
*
* @param thirdStateObject The new encapsulated {@link StateObject} representing the third
* expression
*/
public void setThird(StateObject thirdStateObject) {
StateObject oldThirdStateObject = this.thirdStateObject;
this.thirdStateObject = parent(thirdStateObject);
firePropertyChanged(THIRD_STATE_OBJECT_PROPERTY, oldThirdStateObject, thirdStateObject);
}
@Override
protected void toTextEncapsulatedExpression(Appendable writer) throws IOException {
if (firstStateObject != null) {
firstStateObject.toString(writer);
writer.append(SPACE);
}
writer.append(COMMA);
if (secondStateObject != null) {
writer.append(SPACE);
secondStateObject.toString(writer);
}
writer.append(COMMA);
if (thirdStateObject != null) {
writer.append(SPACE);
thirdStateObject.toString(writer);
}
}
}