| /* |
| * 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.mappings.querykeys; |
| |
| import java.security.AccessController; |
| import java.security.PrivilegedActionException; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| import org.eclipse.persistence.exceptions.ValidationException; |
| import org.eclipse.persistence.expressions.*; |
| import org.eclipse.persistence.internal.expressions.DataExpression; |
| import org.eclipse.persistence.internal.expressions.ExpressionIterator; |
| import org.eclipse.persistence.internal.expressions.ParameterExpression; |
| import org.eclipse.persistence.internal.expressions.TableExpression; |
| import org.eclipse.persistence.internal.helper.DatabaseField; |
| import org.eclipse.persistence.internal.helper.DatabaseTable; |
| import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; |
| import org.eclipse.persistence.internal.security.PrivilegedClassForName; |
| |
| /** |
| * <p> |
| * <b>Purpose</b>: Define an alias to a foreign object. |
| * <p> |
| * <b> Responsibilities</b>: |
| * <ul> |
| * <li> Define the reference class of the foreign object. |
| * </ul> |
| */ |
| public class ForeignReferenceQueryKey extends QueryKey { |
| protected Class referenceClass; |
| protected String referenceClassName; |
| protected Expression joinCriteria; |
| |
| /** |
| * INTERNAL: |
| * Convert all the class-name-based settings in this project to actual class-based |
| * settings |
| * @param classLoader |
| */ |
| @Override |
| public void convertClassNamesToClasses(ClassLoader classLoader){ |
| Class referenceClass = null; |
| try{ |
| if (referenceClassName != null){ |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ |
| try { |
| referenceClass = AccessController.doPrivileged(new PrivilegedClassForName(referenceClassName, true, classLoader)); |
| } catch (PrivilegedActionException exception) { |
| throw ValidationException.classNotFoundWhileConvertingClassNames(referenceClassName, exception.getException()); |
| } |
| } else { |
| referenceClass = PrivilegedAccessHelper.getClassForName(referenceClassName, true, classLoader); |
| } |
| } |
| setReferenceClass(referenceClass); |
| } catch (ClassNotFoundException exc){ |
| throw ValidationException.classNotFoundWhileConvertingClassNames(referenceClassName, exc); |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Return the join expression for the relationship defined by the query key. |
| */ |
| public Expression getJoinCriteria() { |
| return joinCriteria; |
| } |
| |
| /** |
| * PUBLIC: |
| * Return the reference class of the relationship. |
| */ |
| public Class getReferenceClass() { |
| return referenceClass; |
| } |
| |
| /** |
| * PUBLIC: |
| * Return the reference class name of the relationship. |
| */ |
| public String getReferenceClassName() { |
| if (referenceClassName == null && referenceClass != null){ |
| referenceClassName = referenceClass.getName(); |
| } |
| return referenceClassName; |
| } |
| |
| /** |
| * INTERNAL: |
| * override the isForeignReferenceQueryKey() method in the superclass to return true. |
| * @return boolean |
| */ |
| @Override |
| public boolean isForeignReferenceQueryKey() { |
| return true; |
| } |
| |
| /** |
| * PUBLIC: |
| * Set the join expression for the relationship defined by the query key. |
| * <p>Example: |
| * <blockquote><pre> |
| * builder.getField("ADDRESS.ADDRESS_ID").equal(builder.getParameter("EMPLOYEE.ADDR_ID"); |
| * </pre></blockquote> |
| */ |
| public void setJoinCriteria(Expression joinCriteria) { |
| this.joinCriteria = joinCriteria; |
| } |
| |
| /** |
| * PUBLIC: |
| * Set the reference class of the relationship. |
| * This is not required for direct collection query keys. |
| */ |
| public void setReferenceClass(Class referenceClass) { |
| this.referenceClass = referenceClass; |
| } |
| |
| /** |
| * PUBLIC: |
| * Set the reference class name for this relationship |
| * This is used when projects are built without using classes |
| * @param referenceClassName |
| */ |
| public void setReferenceClassName(String referenceClassName) { |
| this.referenceClassName = referenceClassName; |
| } |
| |
| /** |
| * PUBLIC: |
| * Returns the source table. |
| */ |
| public DatabaseTable getSourceTable() { |
| // TODO: Should extract the target table from joinCriteria (if it's not null), |
| // like ManyToManyQueryKey.getRelationTable does. |
| return this.descriptor.getTables().firstElement(); |
| } |
| |
| /** |
| * PUBLIC: |
| * Returns the reference table. |
| */ |
| public DatabaseTable getReferenceTable(ClassDescriptor desc) { |
| // TODO: This won't work for direct collection. |
| // Should extract the target table from joinCriteria (if it's not null), |
| // like ManyToManyQueryKey.getRelationTable does. |
| return desc.getTables().firstElement(); |
| } |
| |
| /** |
| * PUBLIC: |
| * Returns the relation table. |
| * Currently only ManyToMany and OneToOne may have relation table. |
| * The method is overridden to return null for other subclasses. |
| * The returned relationTable still could be null. |
| */ |
| public DatabaseTable getRelationTable(ClassDescriptor referenceDescriptor) { |
| ExpressionIterator expIterator = new ExpressionIterator() { |
| @Override |
| public void iterate(Expression each) { |
| if(each.isTableExpression()) { |
| ((Collection)this.getResult()).add(((TableExpression)each).getTable()); |
| } |
| else if(each.isDataExpression()) { |
| DatabaseField field = ((DataExpression)each).getField(); |
| if(field != null && field.hasTableName()) { |
| ((Collection)this.getResult()).add(field.getTable()); |
| } |
| } else if(each.isParameterExpression()) { |
| DatabaseField field = ((ParameterExpression)each).getField(); |
| if(field != null && field.hasTableName()) { |
| ((Collection)this.getResult()).add(field.getTable()); |
| } |
| } |
| } |
| }; |
| |
| expIterator.setResult(new HashSet()); |
| expIterator.iterateOn(this.joinCriteria); |
| HashSet<DatabaseTable> tables = (HashSet)expIterator.getResult(); |
| |
| DatabaseTable relationTable = null; |
| Iterator<DatabaseTable> it = tables.iterator(); |
| while(it.hasNext()) { |
| DatabaseTable table = it.next(); |
| // neither source nor reference descriptor contains table - must be relationTable |
| if(!descriptor.getTables().contains(table) && !referenceDescriptor.getTables().contains(table)) { |
| relationTable = table; |
| break; |
| } |
| } |
| return relationTable; |
| } |
| } |