| /* |
| * Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 2019 IBM Corporation. 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 from Oracle TopLink |
| package org.eclipse.persistence.internal.queries; |
| |
| import org.eclipse.persistence.exceptions.*; |
| import org.eclipse.persistence.expressions.*; |
| import org.eclipse.persistence.mappings.*; |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.queries.*; |
| import org.eclipse.persistence.internal.expressions.FunctionExpression; |
| import org.eclipse.persistence.internal.expressions.QueryKeyExpression; |
| |
| /** |
| * <b>Purpose</b>: represents an item requested (i.e. field for SELECT) |
| * |
| * @author Doug Clarke |
| * @since 2.0 |
| */ |
| public class ReportItem implements Cloneable, java.io.Serializable { |
| |
| /** Expression (partial) describing the attribute wanted */ |
| protected Expression attributeExpression; |
| |
| /** Name given for item, can be used to retrieve value from result. Useful if same field retrieved multiple times */ |
| protected String name; |
| |
| /** Mapping which relates field to attribute, used to convert value and determine reference descriptor */ |
| protected DatabaseMapping mapping; |
| |
| /** Descriptor for object result that is not based on an expression */ |
| protected ClassDescriptor descriptor; |
| |
| /** Result type for this report item. */ |
| protected Class resultType; |
| /** Stores the Join information for this item */ |
| protected JoinedAttributeManager joinedAttributeManager; |
| |
| /** Stores the row index for this item, given multiple results and joins */ |
| protected int resultIndex; |
| |
| public ReportItem() { |
| super(); |
| } |
| |
| public ReportItem(String name, Expression attributeExpression) { |
| this(); |
| this.name = name; |
| this.attributeExpression = attributeExpression; |
| } |
| |
| @Override |
| public Object clone(){ |
| try{ |
| return super.clone(); |
| } catch (CloneNotSupportedException e) { |
| return null; |
| } |
| } |
| |
| public Expression getAttributeExpression() { |
| return attributeExpression; |
| } |
| |
| public void setAttributeExpression(Expression attributeExpression) { |
| this.attributeExpression = attributeExpression; |
| } |
| |
| public ClassDescriptor getDescriptor(){ |
| return this.descriptor; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the list of expressions that represent elements that are joined because of their |
| * mapping for this query. |
| */ |
| public JoinedAttributeManager getJoinedAttributeManager() { |
| if (this.joinedAttributeManager == null) { |
| this.joinedAttributeManager = new JoinedAttributeManager(); |
| } |
| return this.joinedAttributeManager; |
| } |
| |
| public JoinedAttributeManager getJoinedAttributeManagerInternal(){ |
| return joinedAttributeManager; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return if any attributes are joined. |
| * To avoid the initialization of the JoinedAttributeManager this should be first checked before accessing. |
| */ |
| public boolean hasJoining() { |
| return this.joinedAttributeManager != null; |
| } |
| |
| public DatabaseMapping getMapping() { |
| return mapping; |
| } |
| |
| public String getName() { |
| return name; |
| } |
| |
| public int getResultIndex() { |
| return resultIndex; |
| } |
| |
| public Class getResultType() { |
| return resultType; |
| } |
| |
| /** |
| * INTERNAL: |
| * Looks up mapping for attribute during preExecute of ReportQuery |
| */ |
| public void initialize(ReportQuery query) throws QueryException { |
| if (this.mapping == null) { |
| if (this.attributeExpression != null) { |
| DatabaseMapping mapping = this.attributeExpression.getLeafMapping(query, query.getDescriptor(), query.getSession()); |
| if (mapping == null) { |
| //TODO: This feels like it should be set earlier during ReportItemBuild.visit. Should investigate. |
| if (this.attributeExpression.isExpressionBuilder()) { |
| Class resultClass = ((ExpressionBuilder)this.attributeExpression).getQueryClass(); |
| if (resultClass == null) { |
| resultClass = query.getReferenceClass(); |
| ((ExpressionBuilder)this.attributeExpression).setQueryClass(resultClass); |
| } |
| setDescriptor(query.getSession().getDescriptor(resultClass)); |
| if (getDescriptor().hasInheritance()) { |
| ((ExpressionBuilder)this.attributeExpression).setShouldUseOuterJoinForMultitableInheritance(true); |
| } |
| } |
| } else { |
| if (mapping.isAbstractDirectMapping() || this.attributeExpression.isMapEntryExpression() || mapping.isAggregateObjectMapping() || mapping.isDirectCollectionMapping()){ |
| setMapping(mapping); |
| //Bug4942640 Widen the check to support collection mapping too |
| } else if (mapping.isForeignReferenceMapping()) { |
| // DirectCollectionMapping doesn't have reference descriptor |
| if(mapping.getReferenceDescriptor() != null) { |
| setDescriptor(mapping.getReferenceDescriptor()); |
| if (getDescriptor().hasInheritance()){ |
| ((QueryKeyExpression)this.attributeExpression).setShouldUseOuterJoinForMultitableInheritance(true); |
| } |
| } |
| } else { |
| throw QueryException.invalidExpressionForQueryItem(this.attributeExpression, query); |
| } |
| } |
| if (hasJoining()) { |
| this.joinedAttributeManager.setDescriptor(this.descriptor); |
| this.joinedAttributeManager.setBaseQuery(query); |
| } |
| if (getAttributeExpression() != null){ |
| if (getAttributeExpression().getBuilder().wasQueryClassSetInternally()){ |
| //rebuild if class was not set by user this ensures the query has the same base |
| this.attributeExpression = this.attributeExpression.rebuildOn(query.getExpressionBuilder()); |
| } |
| if (hasJoining()) { |
| this.joinedAttributeManager.setBaseExpressionBuilder(this.attributeExpression.getBuilder()); |
| } |
| } else if (hasJoining()) { |
| this.joinedAttributeManager.setBaseExpressionBuilder(query.getExpressionBuilder()); |
| } |
| if (hasJoining()) { |
| this.joinedAttributeManager.prepareJoinExpressions(query.getSession()); |
| this.joinedAttributeManager.processJoinedMappings(query.getSession()); |
| this.joinedAttributeManager.computeJoiningMappingQueries(query.getSession()); |
| } |
| } |
| } |
| } |
| |
| public boolean isConstructorItem(){ |
| return false; |
| } |
| |
| public void setDescriptor(ClassDescriptor descriptor){ |
| this.descriptor = descriptor; |
| } |
| |
| |
| public void setJoinedAttributeManager(JoinedAttributeManager joinManager){ |
| this.joinedAttributeManager = joinManager; |
| } |
| |
| public void setMapping(DatabaseMapping mapping) { |
| this.mapping = mapping; |
| } |
| |
| public void setResultIndex(int resultIndex) { |
| this.resultIndex = resultIndex; |
| if (hasJoining()) { |
| getJoinedAttributeManager().setParentResultIndex(resultIndex); |
| } |
| } |
| |
| public void setResultType(Class resultType) { |
| this.resultType = resultType; |
| |
| // Set it on the attribute expression as well if it is a function. |
| if (getAttributeExpression()!=null && getAttributeExpression().isFunctionExpression()) { |
| ((FunctionExpression) getAttributeExpression()).setResultType(resultType); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return "ReportQueryItem(" + getName() + " -> " + getAttributeExpression() + ")"; |
| } |
| } |