| /* |
| * Copyright (c) 1998, 2020 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 from Oracle TopLink |
| package org.eclipse.persistence.internal.jpa.parsing; |
| |
| // Java imports |
| import java.util.*; |
| |
| import org.eclipse.persistence.exceptions.JPQLException; |
| import org.eclipse.persistence.queries.ObjectLevelReadQuery; |
| import org.eclipse.persistence.queries.ReportQuery; |
| |
| /** |
| * INTERNAL |
| * <p><b>Purpose</b>: Represent a constructor node (NEW) |
| * <p><b>Responsibilities</b>:<ul> |
| * <li> Generate the correct expression for a constructor |
| * </ul> |
| */ |
| public class ConstructorNode extends Node implements AliasableNode { |
| |
| /** The name of the constructor class. */ |
| private String className = null; |
| |
| /** The list of constructor call argument nodes */ |
| public List constructorItems = new ArrayList(); |
| |
| /** |
| * Return a new ConstructorNode |
| */ |
| public ConstructorNode(String className) { |
| this.className = className; |
| } |
| |
| /** |
| * INTERNAL |
| * Apply this node to the passed query |
| */ |
| @Override |
| public void applyToQuery(ObjectLevelReadQuery theQuery, GenerationContext context) { |
| if (theQuery instanceof ReportQuery) { |
| SelectGenerationContext selectContext = (SelectGenerationContext)context; |
| ReportQuery reportQuery = (ReportQuery)theQuery; |
| reportQuery.beginAddingConstructorArguments( |
| getConstructorClass(context.getParseTreeContext())); |
| for (Iterator i = constructorItems.iterator(); i.hasNext();) { |
| Node node = (Node)i.next(); |
| if (selectingRelationshipField(node, context)) { |
| selectContext.useOuterJoins(); |
| } |
| node.applyToQuery(reportQuery, context); |
| selectContext.dontUseOuterJoins(); |
| } |
| reportQuery.endAddingToConstructorItem(); |
| } |
| } |
| |
| /** |
| * INTERNAL |
| * Validate node and calculate its type. |
| */ |
| @Override |
| public void validate(ParseTreeContext context) { |
| for (Iterator i = constructorItems.iterator(); i.hasNext();) { |
| Node item = (Node)i.next(); |
| item.validate(context); |
| } |
| |
| // Resolve constructor class |
| TypeHelper typeHelper = context.getTypeHelper(); |
| Object type = typeHelper.resolveTypeName(className); |
| if (type == null) { |
| String name = className; |
| // check for inner classes |
| int index = name.lastIndexOf('.'); |
| if (index != -1) { |
| name = name.substring(0, index) + '$' + name.substring(index+1); |
| type = typeHelper.resolveTypeName(name); |
| } |
| } |
| setType(type); |
| } |
| |
| /** |
| * INTERNAL |
| * Is this node a ConstructorNode |
| */ |
| @Override |
| public boolean isConstructorNode() { |
| return true; |
| } |
| |
| /** |
| * INTERNAL |
| * Add an Order By Item to this node |
| */ |
| public void addConstructorItem(Object theNode) { |
| constructorItems.add(theNode); |
| } |
| |
| /** |
| * INTERNAL |
| * Set the list of constructor items of this node. |
| */ |
| public void setConstructorItems(List items) { |
| this.constructorItems = items; |
| } |
| |
| /** |
| * INTERNAL |
| * Get the list of constructor items of this node. |
| */ |
| public List getConstructorItems() { |
| return this.constructorItems; |
| } |
| |
| /** |
| * Check the specific constructor class and return its class instance. |
| * @exception JPQLException if the specified constructor class could not |
| * be found. |
| */ |
| private Class getConstructorClass(ParseTreeContext context) { |
| Object type = getType(); |
| if (type == null) { |
| throw JPQLException.constructorClassNotFound( |
| context.getQueryInfo(), getLine(), getColumn(), className); |
| } |
| return (Class)type; |
| } |
| |
| /** |
| * INTERNAL |
| */ |
| private boolean selectingRelationshipField(Node node, GenerationContext context) { |
| if ((node == null) || !node.isDotNode()) { |
| return false; |
| } |
| |
| TypeHelper typeHelper = context.getParseTreeContext().getTypeHelper(); |
| Node path = node.getLeft(); |
| AttributeNode attribute = (AttributeNode)node.getRight(); |
| return typeHelper.isRelationship(path.getType(), |
| attribute.getAttributeName()); |
| } |
| |
| /** |
| * INTERNAL |
| * Get the string representation of this node. |
| */ |
| @Override |
| public String getAsString() { |
| StringBuilder repr = new StringBuilder(); |
| repr.append("NEW ").append(className); |
| repr.append("("); |
| for (Iterator i = constructorItems.iterator(); i.hasNext();) { |
| Node node = (Node)i.next(); |
| repr.append(node.getAsString()); |
| if (i.hasNext()) { |
| repr.append(", "); |
| } |
| } |
| repr.append(")"); |
| return repr.toString(); |
| } |
| |
| @Override |
| public boolean isAliasableNode(){ |
| return true; |
| } |
| } |