/******************************************************************************* * Copyright (c) 2011, 2015 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 v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * 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><b>BNF:</b> <code><identifier>(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; } /** * {@inheritDoc} */ @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; } /** * {@inheritDoc} */ @Override protected String getQueryBNFId() { return IdentificationVariableBNF.ID; } /** * {@inheritDoc} */ @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()); } /** * {@inheritDoc} */ @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); } }