| /* |
| * 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; |
| |
| import org.eclipse.persistence.jpa.jpql.parser.AbstractExpression; |
| import org.eclipse.persistence.jpa.jpql.parser.JPQLGrammar; |
| import org.eclipse.persistence.jpa.jpql.parser.JPQLStatementBNF; |
| import org.eclipse.persistence.jpa.jpql.tools.model.IJPQLQueryBuilder; |
| import org.eclipse.persistence.jpa.jpql.tools.model.IJPQLQueryFormatter; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractPathExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractSchemaNameStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.AbstractTraverseChildrenVisitor; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.CollectionValuedPathExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.ConstructorExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.EntityTypeLiteralStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.IdentificationVariableStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.JPQLQueryStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.OrderByItemStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.ResultVariableStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.SelectStatementStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.StateFieldPathExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.StateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.TreatExpressionStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.spi.IManagedTypeProvider; |
| import org.eclipse.persistence.jpa.jpql.tools.spi.IMapping; |
| import org.eclipse.persistence.jpa.jpql.tools.spi.IType; |
| |
| /** |
| * The abstract implementation providing refactoring support for JPQL queries. |
| * <p> |
| * Provisional API: This interface is part of an interim API that is still under development and |
| * expected to change significantly before reaching stability. It is available at this early stage |
| * to solicit feedback from pioneering adopters on the understanding that any code that uses this |
| * API will almost certainly be broken (repeatedly) as the API evolves. |
| * |
| * @see DefaultRefactoringTool |
| * @see EclipseLinkRefactoringTool |
| * |
| * @version 2.4 |
| * @since 2.4 |
| * @author Pascal Filion |
| */ |
| public abstract class RefactoringTool extends AbstractRefactoringTool { |
| |
| /** |
| * The builder that creates the {@link StateObject} representation of the JPQL query. |
| */ |
| private IJPQLQueryBuilder jpqlQueryBuilder; |
| |
| /** |
| * The formatter that converts a {@link StateObject} representation of the JPQL query into a |
| * string representation. |
| */ |
| private IJPQLQueryFormatter jpqlQueryFormatter; |
| |
| /** |
| * The editable representation of the JPQL query. |
| */ |
| private JPQLQueryStateObject stateObject; |
| |
| /** |
| * Creates a new <code>RefactoringTool</code>. |
| * |
| * @param managedTypeProvider The external form of a provider that gives access to the JPA metadata |
| * @param jpqlQueryBuilder The builder that creates the {@link StateObject} representation of the |
| * JPQL query |
| * @param jpqlQuery The JPQL query to manipulate |
| */ |
| protected RefactoringTool(IManagedTypeProvider managedTypeProvider, |
| IJPQLQueryBuilder jpqlQueryBuilder, |
| CharSequence jpqlQuery) { |
| |
| this(managedTypeProvider, jpqlQueryBuilder, jpqlQuery, JPQLStatementBNF.ID); |
| } |
| |
| /** |
| * Creates a new <code>RefactoringTool</code>. |
| * |
| * @param managedTypeProvider The external form of a provider that gives access to the JPA metadata |
| * @param jpqlQueryBuilder The builder that creates the {@link StateObject} representation of the |
| * JPQL query |
| * @param jpqlFragment The JPQL query to manipulate or a single JPQL fragment, which is parsed |
| * using the JPQL query BNF identifier by the given ID |
| * @param jpqlQueryBNFId The unique identifier of the {@link |
| * org.eclipse.persistence.jpa.jpql.parser.JPQLQueryBNF JPQLQueryBNF} that determines how to parse the JPQL fragment |
| */ |
| protected RefactoringTool(IManagedTypeProvider managedTypeProvider, |
| IJPQLQueryBuilder jpqlQueryBuilder, |
| CharSequence jpqlFragment, |
| String jpqlQueryBNFId) { |
| |
| super(jpqlFragment, managedTypeProvider, jpqlQueryBNFId); |
| this.jpqlQueryBuilder = jpqlQueryBuilder; |
| } |
| |
| /** |
| * Creates the visitor that will traverse the {@link StateObject} representation of the JPQL |
| * query and will rename the fully qualified class name. |
| * |
| * @param oldClassName The current name of the class to rename |
| * @param newClassName The new name of the class |
| * @return A new {@link ClassNameRenamer} |
| */ |
| protected ClassNameRenamer buildClassNameRenamer(String oldClassName, String newClassName) { |
| return new ClassNameRenamer(oldClassName, newClassName); |
| } |
| |
| /** |
| * Creates the visitor that will traverse the {@link StateObject} representation of the JPQL |
| * query and will rename the entity name. |
| * |
| * @param oldEntityName The current name of the entity to rename |
| * @param newEntityName The new name of the entity |
| * @return A new {@link EntityNameRenamer} |
| */ |
| protected EntityNameRenamer buildEntityNameRenamer(String oldEntityName, String newEntityName) { |
| return new EntityNameRenamer(oldEntityName, newEntityName); |
| } |
| |
| /** |
| * Creates the visitor that will traverse the {@link StateObject} representation of the JPQL |
| * query and will rename the enum constant. |
| * |
| * @param oldClassName The new name of the enum constant |
| * @param newClassName The current name of the enum constant to rename |
| * @return A new {@link EnumConstantRenamer} |
| */ |
| protected EnumConstantRenamer buildEnumConstantRenamer(String oldClassName, String newClassName) { |
| return new EnumConstantRenamer(getManagedTypeProvider(), oldClassName, newClassName); |
| } |
| |
| /** |
| * Creates the visitor that will traverse the {@link StateObject} representation of the JPQL |
| * query and will rename a type's attribute name. |
| * |
| * @param typeName The fully qualified name of the type that got one of its attributes renamed |
| * @param oldFieldName The current name of the attribute to rename |
| * @param newFieldName The new name of the attribute |
| * @return A new {@link org.eclipse.persistence.jpa.jpql.tools.BasicRefactoringTool.AttributeNameRenamer |
| * AttributeNameRenamer} |
| */ |
| protected FieldNameRenamer buildFieldNameRenamer(String typeName, |
| String oldFieldName, |
| String newFieldName) { |
| |
| return new FieldNameRenamer(getManagedTypeProvider(), typeName, oldFieldName, newFieldName); |
| } |
| |
| /** |
| * Creates a new formatter that will convert the {@link StateObject} representation of the JPQL |
| * query, once the refactoring occurred into a string. |
| * |
| * @return A new concrete instance of {@link IJPQLQueryFormatter} |
| */ |
| protected abstract IJPQLQueryFormatter buildFormatter(); |
| |
| /** |
| * Creates a new {@link JPQLQueryContext} that can retrieve information from the declaration |
| * portion of the JPQL query. |
| * <p> |
| * <b>NOTE:</b> This is temporary because the {@link StateObject} API does not have that |
| * knowledge yet. |
| * |
| * @return A new concrete instance of {@link JPQLQueryContext} |
| */ |
| protected abstract JPQLQueryContext buildJPQLQueryContext(); |
| |
| /** |
| * Creates the visitor that will traverse the {@link StateObject} representation of the JPQL |
| * query and will rename a result variable. |
| * |
| * @param oldVariableName The current result variable name |
| * @param newVariableName The new name of the result variable |
| * @return A new {@link ResultVariableNameRenamer} |
| */ |
| protected ResultVariableNameRenamer buildResultVariableNameRenamer(String oldVariableName, |
| String newVariableName) { |
| |
| return new ResultVariableNameRenamer(oldVariableName, newVariableName); |
| } |
| |
| /** |
| * Creates the {@link StateObject} representation of the JPQL fragment to manipulate. |
| * |
| * @return The parsed and editable JPQL query |
| * @see #getStateObject() |
| */ |
| protected JPQLQueryStateObject buildStateObject() { |
| return jpqlQueryBuilder.buildStateObject( |
| getManagedTypeProvider(), |
| getJPQLFragment(), |
| getJPQLQueryBNFId(), |
| isTolerant() |
| ); |
| } |
| |
| /** |
| * Creates the visitor that will traverse the {@link StateObject} representation of the JPQL |
| * query and will rename an identification variable. |
| * |
| * @param oldVariableName The current identification variable name |
| * @param newVariableName The new name of the identification variable |
| * @return A new {@link VariableNameRenamer} |
| */ |
| protected VariableNameRenamer buildVariableNameRenamer(String oldVariableName, |
| String newVariableName) { |
| |
| return new VariableNameRenamer(oldVariableName, newVariableName); |
| } |
| |
| /** |
| * Returns the {@link IJPQLQueryFormatter} that creates an accurate representation of the {@link |
| * StateObject}, i.e. that output the JPQL query with the case used for the JPQL identifier. |
| * |
| * @return An instance of {@link IJPQLQueryFormatter} |
| */ |
| public IJPQLQueryFormatter getFormatter() { |
| if (jpqlQueryFormatter == null) { |
| jpqlQueryFormatter = buildFormatter(); |
| } |
| return jpqlQueryFormatter; |
| } |
| |
| /** |
| * Returns the {@link JPQLGrammar} that is associated with this builder. |
| * |
| * @return The {@link JPQLGrammar} that was used to parse the JPQL query or JPQL fragments |
| */ |
| public JPQLGrammar getGrammar() { |
| return jpqlQueryBuilder.getGrammar(); |
| } |
| |
| /** |
| * Returns the builder that creates the {@link StateObject} representation of the JPQL query. |
| * |
| * @return The builder of the {@link StateObject} to be manipulated |
| */ |
| public IJPQLQueryBuilder getJPQLQueryBuilder() { |
| return jpqlQueryBuilder; |
| } |
| |
| /** |
| * Returns the {@link StateObject} representation of the JPQL query or JPQL fragment that was parsed. |
| * |
| * @return The editable state model |
| */ |
| public JPQLQueryStateObject getStateObject() { |
| if (stateObject == null) { |
| stateObject = buildStateObject(); |
| } |
| return stateObject; |
| } |
| |
| /** |
| * Renames a fully qualified class name. |
| * |
| * @param oldClassName The current fully qualified class name of the class to rename |
| * @param newClassName The new fully qualified class name |
| */ |
| public void renameClassName(String oldClassName, String newClassName) { |
| ClassNameRenamer renamer = buildClassNameRenamer(oldClassName, newClassName); |
| getStateObject().accept(renamer); |
| } |
| |
| /** |
| * Renames a given entity name. |
| * |
| * @param oldEntityName The current name of the entity to rename |
| * @param newEntityName The new name of the entity |
| */ |
| public void renameEntityName(String oldEntityName, String newEntityName) { |
| EntityNameRenamer renamer = buildEntityNameRenamer(oldEntityName, newEntityName); |
| getStateObject().accept(renamer); |
| } |
| |
| /** |
| * Renames an enum constant, which has to be fully qualified. |
| * |
| * @param oldEnumConstant The current fully qualified name of the enum constant to rename |
| * @param newEnumConstant The new fully qualified name of the enum constant |
| */ |
| public void renameEnumConstant(String oldEnumConstant, String newEnumConstant) { |
| EnumConstantRenamer renamer = buildEnumConstantRenamer(oldEnumConstant, newEnumConstant); |
| getStateObject().accept(renamer); |
| } |
| |
| /** |
| * Renames a field from the given type. |
| * |
| * @param type The Java class from which the change originate |
| * @param oldFieldName The current name of the attribute to rename |
| * @param newFieldName The new name of the attribute |
| */ |
| public void renameField(Class<?> type, String oldFieldName, String newFieldName) { |
| renameField(type.getName(), oldFieldName, newFieldName); |
| } |
| |
| /** |
| * Renames a field from the given type. |
| * |
| * @param type The {@link IType} from which the change originate |
| * @param oldFieldName The current name of the attribute to rename |
| * @param newFieldName The new name of the attribute |
| */ |
| public void renameField(IType type, String oldFieldName, String newFieldName) { |
| renameField(type.getName(), oldFieldName, newFieldName); |
| } |
| |
| /** |
| * Renames a field from the given type. |
| * |
| * @param typeName The fully qualified name of the type that got one of its attributes renamed |
| * @param oldFieldName The current name of the attribute to rename |
| * @param newFieldName The new name of the attribute |
| */ |
| public void renameField(String typeName, String oldFieldName, String newFieldName) { |
| FieldNameRenamer renamer = buildFieldNameRenamer(typeName, oldFieldName, newFieldName); |
| getStateObject().accept(renamer); |
| } |
| |
| /** |
| * Renames a result variable name. |
| * |
| * @param oldVariableName The current identification variable name |
| * @param newVariableName The new name of the identification variable |
| */ |
| public void renameResultVariable(String oldVariableName, String newVariableName) { |
| ResultVariableNameRenamer renamer = buildResultVariableNameRenamer(oldVariableName, newVariableName); |
| getStateObject().accept(renamer); |
| } |
| |
| /** |
| * Renames a variable name. |
| * |
| * @param oldVariableName The current identification variable name |
| * @param newVariableName The new name of the identification variable |
| */ |
| public void renameVariable(String oldVariableName, String newVariableName) { |
| VariableNameRenamer renamer = buildVariableNameRenamer(oldVariableName, newVariableName); |
| getStateObject().accept(renamer); |
| } |
| |
| /** |
| * Sets the {@link IJPQLQueryFormatter} that creates an accurate representation of the {@link |
| * StateObject}, i.e. that output the JPQL query with the case used for the JPQL identifier. |
| * |
| * @param jpqlQueryFormatter This formatter converts a {@link StateObject} representation of the |
| * JPQL query into a string representation |
| */ |
| public void setFormatter(IJPQLQueryFormatter jpqlQueryFormatter) { |
| this.jpqlQueryFormatter = jpqlQueryFormatter; |
| } |
| |
| @Override |
| public String toActualText() { |
| return getFormatter().toString(getStateObject()); |
| } |
| |
| /** |
| * This visitor renames a fully qualified class name. |
| */ |
| protected static class ClassNameRenamer extends AbstractTraverseChildrenVisitor { |
| |
| /** |
| * The {@link StateObjectUpdater} that updates the class name when notified. |
| */ |
| protected StateObjectUpdater<ConstructorExpressionStateObject> constructorUpdater; |
| |
| /** |
| * The current name of the class to rename. |
| */ |
| protected final String newClassName; |
| |
| /** |
| * The new name of the class. |
| */ |
| protected final String oldClassName; |
| |
| /** |
| * The {@link StateObjectUpdater} that updates the state field path expression when notified. |
| */ |
| protected StateObjectUpdater<StateFieldPathExpressionStateObject> pathExpressionUpdater; |
| |
| /** |
| * Creates a new <code>ClassNameRenamer</code>. |
| * |
| * @param oldClassName The current name of the class to rename |
| * @param newClassName The new name of the class |
| */ |
| public ClassNameRenamer(String oldClassName, String newClassName) { |
| super(); |
| this.oldClassName = oldClassName; |
| this.newClassName = newClassName; |
| } |
| |
| protected StateObjectUpdater<ConstructorExpressionStateObject> buildConstructorUpdater() { |
| return new StateObjectUpdater<ConstructorExpressionStateObject>() { |
| @Override |
| public void update(ConstructorExpressionStateObject stateObject, CharSequence newValue) { |
| stateObject.setClassName(newValue); |
| } |
| }; |
| } |
| |
| protected StateObjectUpdater<StateFieldPathExpressionStateObject> buildPathExpressionStateObjectUpdater() { |
| return new StateObjectUpdater<StateFieldPathExpressionStateObject>() { |
| @Override |
| public void update(StateFieldPathExpressionStateObject stateObject, CharSequence newValue) { |
| stateObject.setPath(newValue); |
| } |
| }; |
| } |
| |
| protected StateObjectUpdater<ConstructorExpressionStateObject> constructorUpdater() { |
| if (constructorUpdater == null ){ |
| constructorUpdater = buildConstructorUpdater(); |
| } |
| return constructorUpdater; |
| } |
| |
| protected StateObjectUpdater<StateFieldPathExpressionStateObject> pathExpressionUpdater() { |
| if (pathExpressionUpdater == null ){ |
| pathExpressionUpdater = buildPathExpressionStateObjectUpdater(); |
| } |
| return pathExpressionUpdater; |
| } |
| |
| @Override |
| public void visit(ConstructorExpressionStateObject stateObject) { |
| visit(stateObject, stateObject.getClassName(), constructorUpdater()); |
| } |
| |
| @Override |
| public void visit(StateFieldPathExpressionStateObject stateObject) { |
| visit(stateObject, stateObject.getPath(), pathExpressionUpdater()); |
| } |
| |
| /** |
| * Visits the given {@link StateObject} and if its value is the same as the old class name or |
| * if the value represents an inner class of that old class name, then the given {@link |
| * StateObjectUpdater} will be notified to replace the value. |
| * |
| * @param stateObject The {@link StateObject} that is being visited |
| * @param value The value to check if it's the old class name |
| * @param updater The {@link StateObjectUpdater} is notified when to replace the value |
| */ |
| protected <T extends StateObject> void visit(T stateObject, |
| String value, |
| StateObjectUpdater<T> updater) { |
| |
| if (oldClassName.equals(value)) { |
| updater.update(stateObject, newClassName); |
| } |
| else { |
| int index = value.lastIndexOf(AbstractExpression.DOT); |
| |
| // Traverse the value by retrieving a fragment up to the last dot (based on the index) |
| for (; index > -1; index = value.lastIndexOf(AbstractExpression.DOT, index - 1)) { |
| String fragment = value.substring(0, index); |
| |
| if (oldClassName.equals(fragment)) { |
| StringBuilder newValue = new StringBuilder(newClassName); |
| newValue.append(AbstractExpression.DOT); |
| |
| // The path does not end with '.' |
| if (index + 1 < value.length()) { |
| newValue.append(value.substring(index + 1)); |
| } |
| |
| updater.update(stateObject, newValue); |
| break; |
| } |
| // No need to continue the search |
| else if (fragment.length() < oldClassName.length()) { |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * This visitor renames an entity name. There are three possible {@link StateObject StateObjects} |
| * that can represent an entity name: |
| * <ul> |
| * <li> |
| * {@link AbstractSchemaNameStateObject}: |
| * <i>Employee</i> in<br><br> |
| * <code><b>SELECT</b> e<br> |
| * <b>FROM</b> Employee e</code><br><br> |
| * </li> |
| * <li> |
| * {@link EntityTypeLiteralStateObject}: |
| * <i>Exempt</i> in<br><br> |
| * <code><b>SELECT CASE TYPE</b>(e) <b>WHEN</b> Exempt <b>THEN</b> 'Exempt'</code><p> |
| * <code> |
| * <b>ELSE</b> 'NONE'</code><p> |
| * <code> |
| * <b>END</b></code><p> |
| * <code><b>FROM</b> Employee e</code><br><br> |
| * </li> |
| * <li> |
| * {@link IdentificationVariableStateObject}: |
| * <i>Exempt</i> in<br><br> |
| * <code><b>SELECT</b> e<br> |
| * <b>FROM</b> Employee e</code><br> |
| * <b>WHERE TYPE</b>(e) {@literal <>} Exempt |
| * </li> |
| * </ul> |
| */ |
| protected static class EntityNameRenamer extends AbstractTraverseChildrenVisitor { |
| |
| /** |
| * The current name of the entity to rename. |
| */ |
| protected final String newEntityName; |
| |
| /** |
| * The new name of the entity. |
| */ |
| protected final String oldEntityName; |
| |
| /** |
| * Creates a new <code>EntityNameRenamer</code>. |
| * |
| * @param oldEntityName The current name of the entity to rename |
| * @param newEntityName The new name of the entity |
| */ |
| public EntityNameRenamer(String oldEntityName, String newEntityName) { |
| super(); |
| this.oldEntityName = oldEntityName; |
| this.newEntityName = newEntityName; |
| } |
| |
| @Override |
| public void visit(AbstractSchemaNameStateObject stateObject) { |
| if (oldEntityName.equals(stateObject.getText())) { |
| stateObject.setText(newEntityName); |
| } |
| } |
| |
| @Override |
| public void visit(EntityTypeLiteralStateObject stateObject) { |
| if (oldEntityName.equals(stateObject.getText())) { |
| stateObject.setText(newEntityName); |
| } |
| } |
| |
| @Override |
| public void visit(IdentificationVariableStateObject stateObject) { |
| if (oldEntityName.equals(stateObject.getText())) { |
| stateObject.setText(newEntityName); |
| } |
| } |
| |
| @Override |
| public void visit(TreatExpressionStateObject stateObject) { |
| if (oldEntityName.equals(stateObject.getEntityTypeName())) { |
| stateObject.setEntityTypeName(newEntityName); |
| } |
| } |
| } |
| |
| /** |
| * This visitor renames an enum constant. An enum constant is represented by a path expression. |
| */ |
| protected static class EnumConstantRenamer extends AbstractTraverseChildrenVisitor { |
| |
| /** |
| * The external form of a provider that gives access to the JPA metadata. |
| */ |
| protected final IManagedTypeProvider managedTypeProvider; |
| |
| /** |
| * The current name of the enum constant to rename. |
| */ |
| protected final String newEnumConstant; |
| |
| /** |
| * The new name of the enum constant. |
| */ |
| protected final String oldEnumConstant; |
| |
| /** |
| * Creates a new <code>ClassNameRenamer</code>. |
| * |
| * @param managedTypeProvider The provider of managed types |
| * @param oldEnumConstant The new name of the enum constant |
| * @param newEnumConstant The current name of the enum constant to rename |
| */ |
| public EnumConstantRenamer(IManagedTypeProvider managedTypeProvider, |
| String oldEnumConstant, |
| String newEnumConstant) { |
| |
| super(); |
| this.oldEnumConstant = oldEnumConstant; |
| this.newEnumConstant = newEnumConstant; |
| this.managedTypeProvider = managedTypeProvider; |
| } |
| |
| protected void renameEnumConstant(AbstractPathExpressionStateObject stateObject) { |
| |
| String path = stateObject.toString(); |
| |
| if (path.equals(oldEnumConstant)) { |
| |
| IType type = managedTypeProvider.getTypeRepository().getEnumType(path); |
| |
| if (type != null) { |
| stateObject.setPath(newEnumConstant); |
| } |
| } |
| } |
| |
| @Override |
| public void visit(CollectionValuedPathExpressionStateObject stateObject) { |
| renameEnumConstant(stateObject); |
| } |
| |
| @Override |
| public void visit(StateFieldPathExpressionStateObject stateObject) { |
| renameEnumConstant(stateObject); |
| } |
| } |
| |
| /** |
| * This visitor renames any segment of a path expression. |
| */ |
| protected static class FieldNameRenamer extends AbstractTraverseChildrenVisitor { |
| |
| /** |
| * The external form of a provider that gives access to the JPA metadata. |
| */ |
| protected final IManagedTypeProvider managedTypeProvider; |
| |
| /** |
| * The new name of the attribute. |
| */ |
| protected final String newFieldName; |
| |
| /** |
| * The current name of the attribute to rename. |
| */ |
| protected final String oldFieldName; |
| |
| /** |
| * The fully qualified name of the type that got one of its attributes renamed. |
| */ |
| protected final String typeName; |
| |
| /** |
| * Creates a new <code>AttributeNameRenamer</code>. |
| * |
| * @param typeName The fully qualified name of the type that got one of its attributes renamed |
| * @param oldFieldName The current name of the attribute to rename |
| * @param newFieldName The new name of the attribute |
| */ |
| public FieldNameRenamer(IManagedTypeProvider managedTypeProvider, |
| String typeName, |
| String oldFieldName, |
| String newFieldName) { |
| |
| super(); |
| this.typeName = typeName; |
| this.oldFieldName = oldFieldName; |
| this.newFieldName = newFieldName; |
| this.managedTypeProvider = managedTypeProvider; |
| } |
| |
| /** |
| * Performs the rename on the path expression. |
| * |
| * @param stateObject The {@link AbstractPathExpressionStateObject} being visited, which may |
| * have to have its path renamed |
| */ |
| protected void rename(AbstractPathExpressionStateObject stateObject) { |
| |
| // Now traverse the path expression after the identification variable |
| for (int index = 1, count = stateObject.itemsSize(); index < count; index++) { |
| |
| // Retrieve the mapping for the path at the current position |
| IMapping mapping = stateObject.getMapping(index); |
| |
| if (mapping == null) { |
| break; |
| } |
| |
| // The name matches |
| if (mapping.getName().equals(oldFieldName)) { |
| |
| // Make sure the field name is from the right type |
| String parentTypeName = mapping.getParent().getType().getName(); |
| |
| if (parentTypeName.equals(typeName)) { |
| stateObject.setPath(index, newFieldName); |
| break; |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void visit(CollectionValuedPathExpressionStateObject stateObject) { |
| rename(stateObject); |
| } |
| |
| @Override |
| public void visit(StateFieldPathExpressionStateObject stateObject) { |
| rename(stateObject); |
| } |
| } |
| |
| /** |
| * This visitor renames all the result variables found in the JPQL query. |
| */ |
| protected static class ResultVariableNameRenamer extends AbstractTraverseChildrenVisitor { |
| |
| /** |
| * The new name of the result variable. |
| */ |
| protected final String newVariableName; |
| |
| /** |
| * The current result variable name. |
| */ |
| protected final String oldVariableName; |
| |
| /** |
| * Makes sure an identification variable is renamed only when it's used by an order by item. |
| */ |
| protected boolean renameIdentificationVariable; |
| |
| /** |
| * Creates a new <code>ResultVariableNameRenamer</code>. |
| * |
| * @param oldVariableName The current result variable name |
| * @param newVariableName The new name of the result variable |
| */ |
| public ResultVariableNameRenamer(String oldVariableName, String newVariableName) { |
| super(); |
| this.oldVariableName = oldVariableName; |
| this.newVariableName = newVariableName; |
| } |
| |
| @Override |
| public void visit(IdentificationVariableStateObject stateObject) { |
| |
| if (renameIdentificationVariable && |
| oldVariableName.equalsIgnoreCase(stateObject.getText())) { |
| |
| stateObject.setText(newVariableName); |
| } |
| } |
| |
| @Override |
| public void visit(JPQLQueryStateObject stateObject) { |
| if (stateObject.hasQueryStatement()) { |
| stateObject.getQueryStatement().accept(this); |
| } |
| } |
| |
| @Override |
| public void visit(OrderByItemStateObject stateObject) { |
| if (stateObject.hasStateObject()) { |
| stateObject.getStateObject().accept(this); |
| } |
| } |
| |
| @Override |
| public void visit(ResultVariableStateObject stateObject) { |
| if (oldVariableName.equalsIgnoreCase(stateObject.getResultVariable())) { |
| stateObject.setResultVariable(newVariableName); |
| } |
| } |
| |
| @Override |
| public void visit(SelectStatementStateObject stateObject) { |
| |
| // Result variables defined in the SELECT clause |
| stateObject.getSelectClause().accept(this); |
| |
| // Result variables used in the ORDER BY clause |
| if (stateObject.hasOrderByClause()) { |
| renameIdentificationVariable = true; |
| try { |
| stateObject.getOrderByClause().accept(this); |
| } |
| finally { |
| renameIdentificationVariable = false; |
| } |
| } |
| } |
| } |
| |
| /** |
| * This interface is used to transparently push the new value into the {@link StateObject}. |
| */ |
| protected interface StateObjectUpdater<T extends StateObject> { |
| |
| /** |
| * Updates the given {@link StateObject} by updating its state with the given new value. |
| * |
| * @param stateObject The {@link StateObject} to update |
| * @param newValue The new value to push into the object |
| */ |
| void update(T stateObject, CharSequence newValue); |
| } |
| |
| /** |
| * This visitor renames all the identification variables found in the JPQL query. |
| */ |
| protected static class VariableNameRenamer extends AbstractTraverseChildrenVisitor { |
| |
| /** |
| * The new name of the identification variable. |
| */ |
| protected final String newVariableName; |
| |
| /** |
| * The current identification variable name. |
| */ |
| protected final String oldVariableName; |
| |
| /** |
| * Creates a new <code>VariableNameRenamer</code>. |
| * |
| * @param oldVariableName The current identification variable name |
| * @param newVariableName The new name of the identification variable |
| */ |
| public VariableNameRenamer(String oldVariableName, String newVariableName) { |
| super(); |
| this.oldVariableName = oldVariableName; |
| this.newVariableName = newVariableName; |
| } |
| |
| @Override |
| public void visit(CollectionValuedPathExpressionStateObject stateObject) { |
| |
| // Make sure the collection-valued path expression's identification variable was created |
| stateObject.getIdentificationVariable(); |
| |
| super.visit(stateObject); |
| } |
| |
| @Override |
| public void visit(IdentificationVariableStateObject stateObject) { |
| if (oldVariableName.equalsIgnoreCase(stateObject.getText())) { |
| stateObject.setText(newVariableName); |
| } |
| } |
| |
| @Override |
| public void visit(StateFieldPathExpressionStateObject stateObject) { |
| |
| // Make sure the collection-valued path expression's identification variable was created |
| stateObject.getIdentificationVariable(); |
| |
| super.visit(stateObject); |
| } |
| } |
| } |