| /* |
| * 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; |
| |
| import org.eclipse.persistence.jpa.jpql.parser.*; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.JPQLQueryStateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.model.query.StateObject; |
| import org.eclipse.persistence.jpa.jpql.tools.spi.IManagedTypeProvider; |
| |
| /** |
| * An abstract implementation of {@link IJPQLQueryBuilder} that parses a JPQL query or any JPQL |
| * fragments and creates the {@link StateObject} representation by delegating the creation to an |
| * instance of {@link BasicStateObjectBuilder}. |
| * |
| * @see DefaultJPQLQueryBuilder |
| * @see EclipseLinkJPQLQueryBuilder |
| * |
| * @version 2.4 |
| * @since 2.4 |
| * @author Pascal Filion |
| */ |
| public abstract class AbstractJPQLQueryBuilder implements IJPQLQueryBuilder { |
| |
| /** |
| * Keeps a reference for future use. |
| */ |
| private BasicStateObjectBuilder builder; |
| |
| /** |
| * Creates a new <code>AbstractJPQLQueryBuilder</code>. |
| */ |
| protected AbstractJPQLQueryBuilder() { |
| super(); |
| } |
| |
| @Override |
| public ICaseExpressionStateObjectBuilder buildCaseExpressionStateObjectBuilder(StateObject parent) { |
| return new DefaultCaseExpressionStateObjectBuilder(parent); |
| } |
| |
| @Override |
| public JPQLQueryStateObject buildStateObject(IManagedTypeProvider provider, |
| CharSequence jpqlQuery, |
| boolean tolerant) { |
| |
| return buildStateObject(provider, jpqlQuery, JPQLStatementBNF.ID, tolerant); |
| } |
| |
| @Override |
| public JPQLQueryStateObject buildStateObject(IManagedTypeProvider provider, |
| CharSequence jpqlQuery, |
| String queryBNFId, |
| boolean tolerant) { |
| |
| // First parse the JPQL query |
| JPQLExpression jpqlExpression = parse(jpqlQuery, getGrammar(), tolerant); |
| |
| // Now visit the parsed expression and create the state object hierarchy |
| BasicStateObjectBuilder builder = getStateObjectBuilder(); |
| |
| try { |
| builder.jpqlQueryBuilder = this; |
| builder.managedTypeProvider = provider; |
| |
| jpqlExpression.accept(wrap(builder)); |
| |
| return builder.parent; |
| } |
| finally { |
| builder.jpqlQueryBuilder = null; |
| builder.managedTypeProvider = null; |
| builder.parent = null; |
| builder.stateObject = null; |
| } |
| } |
| |
| @Override |
| public StateObject buildStateObject(StateObject parent, |
| CharSequence jpqlFragment, |
| String queryBNFId) { |
| |
| // First parse the JPQL fragment |
| JPQLExpression jpqlExpression = parse(jpqlFragment, parent.getGrammar(), queryBNFId); |
| |
| // We keep track of the old stuff because during the creation of a JPQLQueryStateObject, |
| // it is possible the state model uses this builder to create some objects |
| BasicStateObjectBuilder builder = getStateObjectBuilder(); |
| IJPQLQueryBuilder oldBuilder = builder.jpqlQueryBuilder; |
| IManagedTypeProvider oldProvider = builder.managedTypeProvider; |
| JPQLQueryStateObject oldParent = builder.parent; |
| StateObject oldStateObject = builder.stateObject; |
| |
| try { |
| builder.jpqlQueryBuilder = this; |
| builder.managedTypeProvider = parent.getManagedTypeProvider(); |
| builder.parent = parent.getRoot(); |
| builder.stateObject = parent; |
| |
| // Visit the Expression for which a StateObject is needed |
| jpqlExpression.getQueryStatement().accept(wrap(builder)); |
| |
| return builder.stateObject; |
| } |
| finally { |
| builder.jpqlQueryBuilder = oldBuilder; |
| builder.managedTypeProvider = oldProvider; |
| builder.parent = oldParent; |
| builder.stateObject = oldStateObject; |
| } |
| } |
| |
| /** |
| * Creates the builder that creates the {@link StateObject} for each {@link org.eclipse.persistence.jpa.jpql.parser.Expression Expression}. |
| * |
| * @return The builder that will be visiting the {@link org.eclipse.persistence.jpa.jpql.parser.Expression Expression} |
| */ |
| protected abstract BasicStateObjectBuilder buildStateObjectBuilder(); |
| |
| /** |
| * Returns the builder that creates the {@link StateObject} for each {@link org.eclipse.persistence.jpa.jpql.parser.Expression Expression}. |
| * |
| * @return The builder that will be visiting the {@link org.eclipse.persistence.jpa.jpql.parser.Expression Expression} |
| */ |
| protected final BasicStateObjectBuilder getStateObjectBuilder() { |
| if (builder == null) { |
| builder = buildStateObjectBuilder(); |
| } |
| return builder; |
| } |
| |
| /** |
| * Parses the given JPQL query with tolerant mode turned on. |
| * |
| * @param jpqlQuery The string representation of the JPQL query to parse |
| * @param jpqlGrammar The JPQL grammar that defines how to parse a JPQL query |
| * @param tolerant Determines if the parsing system should be tolerant, meaning if it should try |
| * to parse invalid or incomplete queries |
| * @return The root of the parsed tree representation of the JPQL query |
| */ |
| protected JPQLExpression parse(CharSequence jpqlQuery, JPQLGrammar jpqlGrammar, boolean tolerant) { |
| return new JPQLExpression(jpqlQuery, jpqlGrammar, tolerant); |
| } |
| |
| /** |
| * Parses the given JPQL fragment with tolerant mode turned on. |
| * |
| * @param jpqFragment The string representation of the portion of a JPQL query to parse |
| * @param jpqlGrammar The JPQL grammar that defines how to parse a JPQL query |
| * @param queryBNFId The unique identifier of the {@link JPQLQueryBNF} |
| * @return The root of the parsed tree representation of the JPQL fragment |
| */ |
| protected JPQLExpression parse(CharSequence jpqFragment, |
| JPQLGrammar jpqlGrammar, |
| String queryBNFId) { |
| |
| return new JPQLExpression(jpqFragment, jpqlGrammar, queryBNFId, true); |
| } |
| |
| /** |
| * If a subclass needs to wrap the given {@link BasicStateObjectBuilder} with another visitor can |
| * do so by simply overriding this method. {@link #buildStateObjectBuilder()} can't be easily |
| * overridden with an {@link ExpressionVisitor} due to the constraint on the return type. |
| * |
| * @param builder The builder to wrap |
| * @return By default the given builder is returned |
| */ |
| protected ExpressionVisitor wrap(BasicStateObjectBuilder builder) { |
| return builder; |
| } |
| } |