blob: a25a1bf8510bc3fc777977cb81a4ad5b537e2997 [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 org.eclipse.persistence.jpa.jpql.ExpressionTools;
import org.eclipse.persistence.jpa.jpql.parser.EncapsulatedIdentificationVariableExpression;
import org.eclipse.persistence.jpa.jpql.parser.IdentificationVariableBNF;
import org.eclipse.persistence.jpa.jpql.tools.spi.IManagedType;
import org.eclipse.persistence.jpa.jpql.tools.spi.IType;
import org.eclipse.persistence.jpa.jpql.tools.spi.ITypeDeclaration;
/**
* This object represents an identification variable that is wrapped by a function.
*
* <div><p><b>BNF:</b> <code>&lt;identifier&gt;(identification_variable)</code></p></div>
*
* @see EncapsulatedIdentificationVariableExpression
*
* @version 2.4
* @since 2.4
* @author Pascal Filion
*/
@SuppressWarnings("nls")
public abstract class EncapsulatedIdentificationVariableExpressionStateObject extends AbstractSingleEncapsulatedExpressionStateObject {
/**
* The cached identification variable that is used to make sure it's the same as the one stored
* in the {@link IdentificationVariableStateObject} itself.
*/
private String identificationVariable;
/**
* The {@link IManagedType} mapped to the identification variable if the identification variable
* maps to an entity name.
*/
private IManagedType managedType;
/**
* The cached {@link IType} of the value to resolve.
*/
private IType type;
/**
* The cached {@link ITypeDeclaration} of the value to resolve.
*/
private ITypeDeclaration typeDeclaration;
/**
* Notifies the identification variable property has changed.
*/
public static final String IDENTIFICATION_VARIABLE_PROPERTY = "identificationVariable";
/**
* Creates a new <code>EncapsulatedIdentificationVariableExpressionStateObject</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 EncapsulatedIdentificationVariableExpressionStateObject(StateObject parent) {
super(parent);
}
/**
* Creates a new <code>EncapsulatedIdentificationVariableExpressionStateObject</code>.
*
* @param parent The parent of this state object, which cannot be <code>null</code>
* @param identificationVariable The identification variable
* @exception NullPointerException The given parent cannot be <code>null</code>
*/
protected EncapsulatedIdentificationVariableExpressionStateObject(StateObject parent,
String identificationVariable) {
super(parent);
setIdentificationVariable(identificationVariable);
}
/**
* Makes sure the cached identification variable and the one owned by {@link
* IdentificationVariableStateObject} are the same. If they are not, then clears the cached
* values related to the type.
*/
protected void checkIntegrity() {
if (ExpressionTools.stringsAreDifferentIgnoreCase(identificationVariable, getStateObject().getText())) {
clearResolvedObjects();
identificationVariable = getStateObject().getText();
}
}
/**
* Clears the values related to the managed type and type.
*/
protected void clearResolvedObjects() {
type = null;
managedType = null;
typeDeclaration = null;
}
@Override
public EncapsulatedIdentificationVariableExpression getExpression() {
return (EncapsulatedIdentificationVariableExpression) super.getExpression();
}
/**
* Returns the identification variable.
*
* @return The name of the identification variable
*/
public String getIdentificationVariable() {
identificationVariable = getStateObject().getText();
return identificationVariable;
}
/**
* Returns the {@link IManagedType} associated with the field handled by this object. If this
* object does not handle a field that has a {@link IManagedType}, then <code>null</code> should
* be returned.
* <p>
* For example: "<code><b>SELECT</b> e <b>FROM</b> Employee e</code>", the object for <i>e</i>
* would be returning the {@link IManagedType} for <i>Employee</i>.
*
* @return Either the {@link IManagedType}, if it could be resolved; <code>null</code> otherwise
*/
public IManagedType getManagedType() {
if (managedType != null) {
checkIntegrity();
}
if (managedType == null) {
managedType = resolveManagedType();
}
return managedType;
}
@Override
protected String getQueryBNFId() {
return IdentificationVariableBNF.ID;
}
@Override
public IdentificationVariableStateObject getStateObject() {
return (IdentificationVariableStateObject) super.getStateObject();
}
/**
* Returns the {@link IType} of the field handled by this object.
*
* @return Either the {@link IType} of the identification variable or the {@link IType} for
* {@link IType#UNRESOLVABLE_TYPE} if it could not be resolved
*/
public IType getType() {
if (type != null) {
checkIntegrity();
}
if (type == null) {
type = resolveType();
}
return type;
}
/**
* Returns the {@link ITypeDeclaration} of the field handled by this object.
*
* @return Either the {@link ITypeDeclaration} that was resolved by this object or the {@link
* ITypeDeclaration} for {@link IType#UNRESOLVABLE_TYPE} if it could not be resolved
*/
public ITypeDeclaration getTypeDeclaration() {
if (typeDeclaration != null) {
checkIntegrity();
}
if (typeDeclaration == null) {
typeDeclaration = resolveTypeDeclaration();
}
return typeDeclaration;
}
/**
* Determines whether the identification variable has been defined or not.
*
* @return <code>true</code> if the identification variable has been defined;
* <code>false</code> otherwise
*/
public boolean hasIdentificationVariable() {
return ExpressionTools.stringIsNotEmpty(getIdentificationVariable());
}
@Override
protected void initialize() {
super.initialize();
setStateObject(new IdentificationVariableStateObject(this));
}
/**
* Retrieves the {@link IManagedType} that is mapped to the identification variable, if and only
* if the identification variable is used to declare an entity.
*
* @return Either the {@link IManagedType} declared by the identification variable or <code>null</code>
* if it could not be resolved
*/
protected IManagedType resolveManagedType() {
return getManagedTypeProvider().getManagedType(getType());
}
/**
* Resolves the {@link IType} of the property handled by this object.
*
* @return Either the {@link IType} that was resolved by this object or the {@link IType} for
* {@link IType#UNRESOLVABLE_TYPE} if it could not be resolved
*/
protected IType resolveType() {
return getTypeDeclaration().getType();
}
/**
* Resolves the {@link ITypeDeclaration} of the property handled by this object.
*
* @return Either the {@link ITypeDeclaration} that was resolved by this object or the {@link
* ITypeDeclaration} for {@link IType#UNRESOLVABLE_TYPE} if it could not be resolved
*/
protected ITypeDeclaration resolveTypeDeclaration() {
return getStateObject().getTypeDeclaration();
}
/**
* Sets the identification variable of this encapsulated expression.
*
* @param identificationVariable The name of the identification variable
*/
public void setIdentificationVariable(String identificationVariable) {
clearResolvedObjects();
String oldIdentificationVariable = this.identificationVariable;
this.identificationVariable = identificationVariable;
getStateObject().setText(identificationVariable);
firePropertyChanged(IDENTIFICATION_VARIABLE_PROPERTY, oldIdentificationVariable, identificationVariable);
}
}