org.eclipse.persistence.mappings.querykeys.ForeignReferenceQueryKey Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* Copyright (c) 1998, 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 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;
/**
*
* Purpose: Define an alias to a foreign object.
*
* Responsibilities:
*
* - Define the reference class of the foreign object.
*
*/
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
*/
@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.
* Example:
*
* builder.getField("ADDRESS.ADDRESS_ID").equal(builder.getParameter("EMPLOYEE.ADDR_ID");
*
*/
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
*/
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 tables = (HashSet)expIterator.getResult();
DatabaseTable relationTable = null;
Iterator 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;
}
}