All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.descriptors.ReturningPolicy Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*
 * Copyright (c) 1998, 2018 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.descriptors;

import java.io.Serializable;
import java.util.*;
import org.eclipse.persistence.internal.databaseaccess.DatabasePlatform;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.mappings.*;
import org.eclipse.persistence.internal.descriptors.OptimisticLockingPolicy;
import org.eclipse.persistence.internal.databaseaccess.DatabaseCall;
import org.eclipse.persistence.queries.*;

/**
 * 

Purpose: * Allows for INSERT or UPDATE operations to return values back into the object being written. * This allows for table default values, trigger or stored procedures computed values to be set back * into the object. * This can be used with generated SQL on the Oracle platform using the RETURNING clause, * or through stored procedures on other platforms. * * @since TopLink 10.1.3 */ public class ReturningPolicy implements Serializable, Cloneable { protected static final int INSERT = 0; protected static final int UPDATE = 1; protected static final int NUM_OPERATIONS = 2; protected static final int RETURN_ONLY = 0; protected static final int WRITE_RETURN = 1; protected static final int MAPPED = 2; protected static final int UNMAPPED = 3; protected static final int ALL = 4; protected static final int MAIN_SIZE = 5; /** owner of the policy */ protected ClassDescriptor descriptor; /** * Stores an object of type Info for every call to any of addField.. methods. * Should be filled out before initialize() is called: * fields added after initialization are ignored. */ protected List infos = new ArrayList(); /** * The following attributes are initialized by initialize() method. * Contains the actual DatabaseFields to be returned. * Populated during descriptor initialization using infos. * Here's the order: *

     * main[INSERT][RETURN_ONLY]  main[INSERT][WRITE_RETURN]  main[INSERT][MAPPED]    main[INSERT][UNMAPPED]    main[INSERT][ALL]
     * main[UPDATE][RETURN_ONLY]  main[UPDATE][WRITE_RETURN]  main[UPDATE][MAPPED]    main[UPDATE][UNMAPPED]    main[UPDATE][ALL]
     * 
* After initialization main[UPDATE,WRITE_RETURN] will contain all DatabaseFields that should be * returned on Update as read-write. *
     * main[i][RETURN_ONLY] + main[i][WRITE_RETURN] = main[i][MAPPED]
     * main[i][MAPPED] + main[i][UNMAPPED] = main[i][ALL]
     * 
*/ protected Collection[][] main; /** * maps ClassDescriptor's tables into Vectors of fields to be used for call generation. * Lazily initialized array [NUM_OPERATIONS] */ protected Map>[] tableToFieldsForGenerationMap; /** indicates whether ReturningPolicy is used for generation of the PK. */ protected boolean isUsedToSetPrimaryKey; /** contains all default table the returning fields that are either unmapped or mapped supplied with types. */ protected Map fieldsNotFromDescriptor_DefaultTable; /** contains all the other tables returning fields that are either unmapped or mapped supplied with types. */ protected Map fieldsNotFromDescriptor_OtherTables; public ReturningPolicy() { super(); } /** * PUBLIC: * Return the owner of the policy. */ public ClassDescriptor getDescriptor() { return descriptor; } /** * INTERNAL: */ protected void fieldIsNotFromDescriptor(DatabaseField field) { if (field.getTable().equals(getDescriptor().getDefaultTable())) { if (this.fieldsNotFromDescriptor_DefaultTable == null) { this.fieldsNotFromDescriptor_DefaultTable = new HashMap(); } this.fieldsNotFromDescriptor_DefaultTable.put(field, field); } else { if (this.fieldsNotFromDescriptor_OtherTables == null) { this.fieldsNotFromDescriptor_OtherTables = new HashMap(); } this.fieldsNotFromDescriptor_OtherTables.put(field, field); } } /** * INTERNAL: */ public Vector getFieldsToGenerateInsert(DatabaseTable table) { return getVectorOfFieldsToGenerate(INSERT, table); } /** * INTERNAL: */ public Vector getFieldsToGenerateUpdate(DatabaseTable table) { return getVectorOfFieldsToGenerate(UPDATE, table); } /** * INTERNAL: */ public List getFieldInfos() { return infos; } /** * INTERNAL: */ public void setFieldInfos(List infos) { this.infos = infos; } /** * INTERNAL: * Used for testing only */ public boolean hasEqualFieldInfos(ReturningPolicy returningPolicyToCompare) { return hasEqualFieldInfos(returningPolicyToCompare.getFieldInfos()); } /** * INTERNAL: * Used for testing only */ public boolean hasEqualFieldInfos(List infosToCompare) { return areCollectionsEqualAsSets(getFieldInfos(), infosToCompare); } /** * INTERNAL: * Compares two Collections as sets (ignoring the order of the elements). * Note that the passed Collections are cloned. * Used for testing only. */ public static boolean areCollectionsEqualAsSets(Collection col1, Collection col2) { if (col1 == col2) { return true; } if (col1.size() != col2.size()) { return false; } Collection c1 = new ArrayList(col1); Collection c2 = new ArrayList(col2); for (Iterator i = c1.iterator(); i.hasNext();) { Object o = i.next(); c2.remove(o); } return c2.isEmpty(); } /** * INTERNAL: */ protected Vector getVectorOfFieldsToGenerate(int operation, DatabaseTable table) { if (this.main[operation][ALL] == null) { return null; } if (this.tableToFieldsForGenerationMap == null) { // the method is called for the first time tableToFieldsForGenerationMap = new HashMap[NUM_OPERATIONS]; } if (this.tableToFieldsForGenerationMap[operation] == null) { // the method is called for the first time for this operation this.tableToFieldsForGenerationMap[operation] = new HashMap(); } Vector fieldsForGeneration = this.tableToFieldsForGenerationMap[operation].get(table); if (fieldsForGeneration == null) { // the method is called for the first time for this operation and this table fieldsForGeneration = new NonSynchronizedVector(); Iterator it = this.main[operation][ALL].iterator(); while (it.hasNext()) { DatabaseField field = (DatabaseField)it.next(); if (field.getTable().equals(table)) { fieldsForGeneration.add(field); } } this.tableToFieldsForGenerationMap[operation].put(table, fieldsForGeneration); } return fieldsForGeneration; } /** * INTERNAL: */ public Collection getFieldsToMergeInsert() { return main[INSERT][MAPPED]; } /** * INTERNAL: */ public Collection getFieldsToMergeUpdate() { return main[UPDATE][MAPPED]; } /** * INTERNAL: * Normally cloned when not yet initialized. * If initialized ReturningPolicy cloned then the clone should be re-initialized. */ public Object clone() { try { return super.clone(); } catch (Exception exception) { throw new InternalError("clone failed"); } } /** * INTERNAL: */ public void setDescriptor(ClassDescriptor descriptor) { this.descriptor = descriptor; } /** * PUBLIC: * Define that the field will be returned from an insert operation. */ public void addFieldForInsert(String qualifiedName) { addFieldForInsert(qualifiedName, null); } /** * PUBLIC: * Define that the field will be returned from an insert operation. * The type may be required to bind the output parameter if not known by the mapping. */ public void addFieldForInsert(String qualifiedName, Class type) { addFieldForInsert(createField(qualifiedName, type)); } /** * PUBLIC: * Define that the field will be returned from an insert operation. */ public void addFieldForInsert(DatabaseField field) { addField(field, true, false, false); } /** * PUBLIC: * Define that the field will be returned from an insert operation. * A field added with addFieldForInsertReturnOnly method * is excluded from INSERT clause during SQL generation. */ public void addFieldForInsertReturnOnly(String qualifiedName) { addFieldForInsertReturnOnly(qualifiedName, null); } /** * PUBLIC: * Define that the field will be returned from an insert operation. * A field added with addFieldForInsertReturnOnly method * is excluded from INSERT clause during SQL generation. * The type may be required to bind the output parameter if not known by the mapping. */ public void addFieldForInsertReturnOnly(String qualifiedName, Class type) { addFieldForInsertReturnOnly(createField(qualifiedName, type)); } /** * PUBLIC: * Define that the field will be returned from an insert operation. * A field added with addFieldForInsertReturnOnly method * is excluded from INSERT clause during SQL generation. */ public void addFieldForInsertReturnOnly(DatabaseField field) { addField(field, true, true, false); } /** * PUBLIC: * Define that the field will be returned from an update operation. */ public void addFieldForUpdate(String qualifiedName) { addFieldForUpdate(qualifiedName, null); } /** * PUBLIC: * Define that the field will be returned from an update operation. * The type may be required to bind the output parameter if not known by the mapping. */ public void addFieldForUpdate(String qualifiedName, Class type) { addFieldForUpdate(createField(qualifiedName, type)); } /** * PUBLIC: * Define that the field will be returned from an update operation. */ public void addFieldForUpdate(DatabaseField field) { addField(field, false, false, true); } /** * INTERNAL: */ protected void addField(DatabaseField field, boolean isInsert, boolean isInsertModeReturnOnly, boolean isUpdate) { getFieldInfos().add(new Info(field, isInsert, isInsertModeReturnOnly, isUpdate)); } /** * INTERNAL: */ public static class Info implements Cloneable { private DatabaseField field; private boolean isInsert; private boolean isInsertModeReturnOnly; private boolean isUpdate; private Class referenceClass; private String referenceClassName; Info() { super(); } Info(DatabaseField field, boolean isInsert, boolean isInsertModeReturnOnly, boolean isUpdate) { this.field = field; if (field != null) { if (field.getType() != null) { setReferenceClass(field.getType()); } } this.isInsert = isInsert; this.isInsertModeReturnOnly = isInsertModeReturnOnly; this.isUpdate = isUpdate; } public DatabaseField getField() { return field; } public void setField(DatabaseField field) { this.field = field; if ((field.getType() == null) && (referenceClass != null)) { field.setType(referenceClass); } } public boolean isInsert() { return isInsert; } public void setIsInsert(boolean isInsert) { this.isInsert = isInsert; } public boolean isInsertModeReturnOnly() { return isInsertModeReturnOnly; } public void setIsInsertModeReturnOnly(boolean isInsertModeReturnOnly) { this.isInsertModeReturnOnly = isInsertModeReturnOnly; } public boolean isUpdate() { return isUpdate; } public void setIsUpdate(boolean isUpdate) { this.isUpdate = isUpdate; } public Class getReferenceClass() { return referenceClass; } public void setReferenceClass(Class referenceClass) { this.referenceClass = referenceClass; if (referenceClass != null) { this.referenceClassName = referenceClass.getName(); } } public String getReferenceClassName() { return referenceClassName; } public void setReferenceClassName(String referenceClassName) { this.referenceClassName = referenceClassName; } // operation is INSERT or UPDATE (0 or 1) boolean is(int operation, int stateToCheck) { if (operation == INSERT) { if (isInsert) { if (stateToCheck == RETURN_ONLY) { return isInsertModeReturnOnly; } else { return !isInsertModeReturnOnly; } } } else { if (isUpdate) { return stateToCheck == WRITE_RETURN; } } return false; } // operation is INSERT or UPDATE (0 or 1) boolean is(int operation) { if (operation == INSERT) { return isInsert; } else { return isUpdate; } } /** * INTERNAL: */ public Object clone() { try { return super.clone(); } catch (Exception exception) { throw new InternalError("clone failed"); } } public boolean equals(Object objectToCompare) { if (objectToCompare instanceof Info) { return equals((Info)objectToCompare); } else { return false; } } boolean equals(Info infoToCompare) { if (this == infoToCompare) { return true; } if (!getField().equals(infoToCompare.getField())) { return false; } if ((getField().getType() == null) && (infoToCompare.getField().getType() != null)) { return false; } if ((getField().getType() != null) && !getField().getType().equals(infoToCompare.getField().getType())) { return false; } if (isInsert() != infoToCompare.isInsert()) { return false; } if (isInsertModeReturnOnly() != infoToCompare.isInsertModeReturnOnly()) { return false; } if (isUpdate() != infoToCompare.isUpdate()) { return false; } return true; } @Override public int hashCode() { DatabaseField field = getField(); Class type = field != null ? field.getType() : null; boolean isInsert = isInsert(); boolean isInsertModeReturnOnly = isInsertModeReturnOnly(); boolean isUpdate = isUpdate(); int result = field != null ? field.hashCode() : 0; result = 31 * result + (type != null ? type.hashCode() : 0); result = 31 * result + (isInsert ? 1 : 0); result = 31 * result + (isInsertModeReturnOnly ? 1 : 0); result = 31 * result + (isUpdate ? 1 : 0); return result; } } /** * INTERNAL: */ // precondition: info1.field.equals(info2.field); static Info mergeInfos(Info info1, Info info2, AbstractSession session, ClassDescriptor descriptor) { boolean ok = true; DatabaseField fieldMerged = info1.getField(); if (info2.getField().getType() != null) { if (info1.getField().getType() == null) { fieldMerged = info2.field; } else if (!info1.getField().getType().equals(info2.getField().getType())) { session.getIntegrityChecker().handleError(DescriptorException.returningPolicyFieldTypeConflict(info1.getField().getName(), info1.getField().getType().getName(), info2.getField().getType().getName(), descriptor)); ok = false; } } boolean isInsertMerged = false; boolean isInsertModeReturnOnlyMerged = false; if (info1.isInsert() && !info2.isInsert()) { isInsertMerged = true; isInsertModeReturnOnlyMerged = info1.isInsertModeReturnOnly(); } else if (!info1.isInsert() && info2.isInsert()) { isInsertMerged = true; isInsertModeReturnOnlyMerged = info2.isInsertModeReturnOnly(); } else if (info1.isInsert() && info2.isInsert()) { isInsertMerged = true; isInsertModeReturnOnlyMerged = info1.isInsertModeReturnOnly(); if (info1.isInsertModeReturnOnly() != info2.isInsertModeReturnOnly()) { session.getIntegrityChecker().handleError(DescriptorException.returningPolicyFieldInsertConflict(info1.getField().getName(), descriptor)); ok = false; } } if (ok) { // merging boolean isUpdateMerged = info1.isUpdate() || info2.isUpdate(); return new Info(fieldMerged, isInsertMerged, isInsertModeReturnOnlyMerged, isUpdateMerged); } else { // there is a problem - can't merge return null; } } /** * INTERNAL: */ // used only on equal fields: field1.equals(field2) static protected boolean isThereATypeConflict(DatabaseField field1, DatabaseField field2) { return (field1.getType() != null) && (field2.getType() != null) && !field1.getType().equals(field2.getType()); } /** * INTERNAL: */ protected DatabaseField createField(String qualifiedName, Class type) { DatabaseField field = new DatabaseField(qualifiedName); field.setType(type); return field; } /** * INTERNAL: */ protected Collection createCollection() { return new HashSet(); } // precondition field != null protected void addFieldToMain(int operation, int state, DatabaseField field) { if (main[operation][state] == null) { main[operation][state] = createCollection(); } main[operation][state].add(field); } protected void addCollectionToMain(int operation, int state, Collection collection) { if ((collection == null) || collection.isEmpty()) { return; } if (main[operation][state] == null) { main[operation][state] = createCollection(); } main[operation][state].addAll(collection); } protected void addMappedFieldToMain(DatabaseField field, Info info) { for (int operation = INSERT; operation <= UPDATE; operation++) { for (int state = RETURN_ONLY; state <= WRITE_RETURN; state++) { if (info.is(operation, state)) { addFieldToMain(operation, state, field); addFieldToMain(operation, MAPPED, field); addFieldToMain(operation, ALL, field); } } } } protected void addUnmappedFieldToMain(DatabaseField field, Info info) { for (int operation = INSERT; operation <= UPDATE; operation++) { if (info.is(operation)) { addFieldToMain(operation, UNMAPPED, field); addFieldToMain(operation, ALL, field); } } } protected Hashtable removeDuplicateAndValidateInfos(AbstractSession session) { Hashtable infoHashtable = new Hashtable(); for (int i = 0; i < infos.size(); i++) { Info info1 = infos.get(i); info1 = (Info)info1.clone(); DatabaseField descField = getDescriptor().buildField(info1.getField()); if(info1.getField().getType() == null) { info1.setField(descField); } else { // keep the original type if specified info1.getField().setName(descField.getName()); info1.getField().setTableName(getDescriptor().getDefaultTable().getQualifiedNameDelimited(session.getPlatform())); } Info info2 = (Info)infoHashtable.get(info1.getField()); if (info2 == null) { infoHashtable.put(info1.getField(), info1); } else { Info infoMerged = mergeInfos(info1, info2, session, getDescriptor()); if (infoMerged != null) { // substitute info2 with infoMerged infoHashtable.put(infoMerged.getField(), infoMerged); } else { // couldn't merge info1 and info2 due to a conflict. // substitute info2 with info1 infoHashtable.put(info1.getField(), info1); } } } return infoHashtable; } /** * INTERNAL: */ public void initialize(AbstractSession session) { clearInitialization(); main = new Collection[NUM_OPERATIONS][MAIN_SIZE]; // The order of descriptor initialization guarantees initialization of Parent before children. // main array is copied from Parent's ReturningPolicy if (getDescriptor().isChildDescriptor()) { ClassDescriptor parentDescriptor = getDescriptor().getInheritancePolicy().getParentDescriptor(); if (parentDescriptor.hasReturningPolicy()) { copyMainFrom(parentDescriptor.getReturningPolicy()); } } if (!infos.isEmpty()) { Hashtable infoHashtable = removeDuplicateAndValidateInfos(session); Hashtable infoHashtableUnmapped = (Hashtable)infoHashtable.clone(); for (Enumeration fields = getDescriptor().getFields().elements(); fields.hasMoreElements();) { DatabaseField field = (DatabaseField)fields.nextElement(); Info info = (Info)infoHashtableUnmapped.get(field); if (info != null) { infoHashtableUnmapped.remove(field); if (verifyFieldAndMapping(session, field)) { if (info.getField().getType() == null) { addMappedFieldToMain(field, info); } else { addMappedFieldToMain(info.getField(), info); fieldIsNotFromDescriptor(info.getField()); } } } } if (!infoHashtableUnmapped.isEmpty()) { Enumeration fields = infoHashtableUnmapped.keys(); while (fields.hasMoreElements()) { DatabaseField field = (DatabaseField)fields.nextElement(); Info info = (Info)infoHashtableUnmapped.get(field); if (verifyField(session, field, getDescriptor())) { if (field.getType() != null) { addUnmappedFieldToMain(field, info); fieldIsNotFromDescriptor(field); session.log(SessionLog.FINEST, SessionLog.QUERY, "added_unmapped_field_to_returning_policy", info.toString(), getDescriptor().getJavaClassName()); } else { if (getDescriptor().isReturnTypeRequiredForReturningPolicy()) { session.getIntegrityChecker().handleError(DescriptorException.returningPolicyUnmappedFieldTypeNotSet(field.getName(), getDescriptor())); } } } } } } initializeIsUsedToSetPrimaryKey(); } protected void copyMainFrom(ReturningPolicy policy) { Collection[][] mainToCopy = policy.main; for (int operation = INSERT; operation <= UPDATE; operation++) { for (int state = RETURN_ONLY; state < MAIN_SIZE; state++) { addCollectionToMain(operation, state, mainToCopy[operation][state]); } } } /** * INTERNAL: * Both ReturningPolicies should be initialized */ public boolean hasEqualMains(ReturningPolicy policy) { Collection[][] mainToCompare = policy.main; if (main == mainToCompare) { return true; } for (int operation = INSERT; operation <= UPDATE; operation++) { for (int state = RETURN_ONLY; state < MAIN_SIZE; state++) { if ((main[operation][state] == null) && (mainToCompare[operation][state] != null)) { return false; } if ((main[operation][state] != null) && (mainToCompare[operation][state] == null)) { return false; } if (!main[operation][state].equals(mainToCompare[operation][state])) { return false; } } } // now compare types Hashtable allFields = new Hashtable(); for (int operation = INSERT; operation <= UPDATE; operation++) { if (main[operation][ALL] != null) { Iterator it = main[operation][ALL].iterator(); while (it.hasNext()) { DatabaseField field = (DatabaseField)it.next(); allFields.put(field, field); } } } for (int operation = INSERT; operation <= UPDATE; operation++) { if (mainToCompare[operation][ALL] != null) { Iterator it = mainToCompare[operation][ALL].iterator(); while (it.hasNext()) { DatabaseField fieldToCompare = (DatabaseField)it.next(); DatabaseField field = (DatabaseField)allFields.get(fieldToCompare); if (!field.getType().equals(fieldToCompare.getType())) { return false; } } } } return true; } /** * INTERNAL: */ public void trimModifyRowForInsert(AbstractRecord modifyRow) { trimModifyRow(modifyRow, INSERT); } // operation should be either INSERT or UPDATE protected void trimModifyRow(AbstractRecord modifyRow, int operation) { if ((modifyRow == null) || modifyRow.isEmpty()) { return; } Collection fields = main[operation][RETURN_ONLY]; if ((fields == null) || fields.isEmpty()) { return; } for (int i = modifyRow.size() - 1; i >= 0; i--) { DatabaseField field = modifyRow.getFields().get(i); if (fields.contains(field)) { modifyRow.remove(field); } } } /** * PUBLIC: */ public boolean isUsedToSetPrimaryKey() { return isUsedToSetPrimaryKey; } // only infos is filled out protected void clearInitialization() { this.main = null; this.tableToFieldsForGenerationMap = null; this.fieldsNotFromDescriptor_DefaultTable = null; this.fieldsNotFromDescriptor_OtherTables = null; } protected void initializeIsUsedToSetPrimaryKey() { this.isUsedToSetPrimaryKey = false; if ((main[INSERT][MAPPED] == null) || main[INSERT][MAPPED].isEmpty()) { return; } List primaryKeys = getDescriptor().getPrimaryKeyFields(); for (int index = 0; (index < primaryKeys.size()) && !isUsedToSetPrimaryKey; index++) { this.isUsedToSetPrimaryKey = main[INSERT][MAPPED].contains(primaryKeys.get(index)); } } protected boolean verifyFieldAndMapping(AbstractSession session, DatabaseField field) { boolean ok = true; verifyField(session, field, getDescriptor()); DatabaseMapping mapping; List readOnlyMappings = getDescriptor().getObjectBuilder().getReadOnlyMappingsForField(field); if (readOnlyMappings != null) { for (int j = 0; j < readOnlyMappings.size(); j++) { mapping = (DatabaseMapping)readOnlyMappings.get(j); ok &= verifyFieldAndMapping(session, field, getDescriptor(), mapping); } } mapping = getDescriptor().getObjectBuilder().getMappingForField(field); if (mapping != null) { ok &= verifyFieldAndMapping(session, field, getDescriptor(), mapping); } return ok; } protected static boolean verifyFieldAndMapping(AbstractSession session, DatabaseField field, ClassDescriptor descriptor, DatabaseMapping mapping) { verifyField(session, field, descriptor); while (mapping.isAggregateObjectMapping()) { ClassDescriptor referenceDescriptor = ((AggregateObjectMapping)mapping).getReferenceDescriptor(); mapping = referenceDescriptor.getObjectBuilder().getMappingForField(field); verifyFieldAndMapping(session, field, referenceDescriptor, mapping); } if (!mapping.isDirectToFieldMapping() && !mapping.isTransformationMapping()) { String mappingTypeName = Helper.getShortClassName(mapping); session.getIntegrityChecker().handleError(DescriptorException.returningPolicyMappingNotSupported(field.getName(), mappingTypeName, mapping)); return false; } else { return true; } } protected static boolean verifyField(AbstractSession session, DatabaseField field, ClassDescriptor descriptor) { boolean ok = true; if (field.equals(descriptor.getSequenceNumberField())) { ok = false; session.getIntegrityChecker().handleError(DescriptorException.returningPolicyFieldNotSupported(field.getName(), descriptor)); } else if (descriptor.hasInheritance() && field.equals(descriptor.getInheritancePolicy().getClassIndicatorField())) { ok = false; session.getIntegrityChecker().handleError(DescriptorException.returningPolicyFieldNotSupported(field.getName(), descriptor)); } else if (descriptor.usesOptimisticLocking()) { OptimisticLockingPolicy optimisticLockingPolicy = descriptor.getOptimisticLockingPolicy(); if (optimisticLockingPolicy instanceof VersionLockingPolicy) { VersionLockingPolicy versionLockingPolicy = (VersionLockingPolicy)optimisticLockingPolicy; if (field.equals(versionLockingPolicy.getWriteLockField())) { ok = false; session.getIntegrityChecker().handleError(DescriptorException.returningPolicyFieldNotSupported(field.getName(), descriptor)); } } } return ok; } /** * INTERNAL: */ public void validationAfterDescriptorInitialization(AbstractSession session) { Hashtable mapped = new Hashtable(); for (int operation = INSERT; operation <= UPDATE; operation++) { if ((main[operation][MAPPED] != null) && !main[operation][MAPPED].isEmpty()) { Iterator it = main[operation][MAPPED].iterator(); while (it.hasNext()) { DatabaseField field = (DatabaseField)it.next(); mapped.put(field, field); } } } if (!mapped.isEmpty()) { for (Enumeration fields = getDescriptor().getFields().elements(); fields.hasMoreElements();) { DatabaseField fieldInDescriptor = (DatabaseField)fields.nextElement(); DatabaseField fieldInMain = (DatabaseField)mapped.get(fieldInDescriptor); if (fieldInMain != null) { if (fieldInMain.getType() == null) { if (getDescriptor().isReturnTypeRequiredForReturningPolicy()) { session.getIntegrityChecker().handleError(DescriptorException.returningPolicyMappedFieldTypeNotSet(fieldInMain.getName(), getDescriptor())); } } else if (isThereATypeConflict(fieldInMain, fieldInDescriptor)) { session.getIntegrityChecker().handleError(DescriptorException.returningPolicyAndDescriptorFieldTypeConflict(fieldInMain.getName(), fieldInMain.getType().getName(), fieldInDescriptor.getType().getName(), getDescriptor())); } } } } if (!(session.getDatasourcePlatform() instanceof DatabasePlatform)) { // don't attempt further diagnostics on non-relational platforms return; } WriteObjectQuery[] query = { getDescriptor().getQueryManager().getInsertQuery(), getDescriptor().getQueryManager().getUpdateQuery() }; String[] queryTypeName = { "InsertObjectQuery", "UpdateObjectQuery" }; for (int operation = INSERT; operation <= UPDATE; operation++) { if ((main[operation][ALL] != null) && !main[operation][ALL].isEmpty()) { // this operation requires some fields to be returned if ((query[operation] == null) || (query[operation].getDatasourceCall() == null)) { if (!session.getPlatform().canBuildCallWithReturning()) { session.getIntegrityChecker().handleError(DescriptorException.noCustomQueryForReturningPolicy(queryTypeName[operation], Helper.getShortClassName(session.getPlatform()), getDescriptor())); } } else if (query[operation].getDatasourceCall() instanceof StoredProcedureCall) { // SQLCall with custom SQL calculates its outputRowFields later (in prepare() method) - // that's why SQLCall can't be verified here. DatabaseCall customCall = (DatabaseCall)query[operation].getDatasourceCall(); Enumeration outputRowFields = customCall.getOutputRowFields().elements(); Collection notFoundInOutputRow = createCollection(); notFoundInOutputRow.addAll(main[operation][ALL]); while (outputRowFields.hasMoreElements()) { notFoundInOutputRow.remove(outputRowFields.nextElement()); } if (!notFoundInOutputRow.isEmpty()) { Iterator it = notFoundInOutputRow.iterator(); while (it.hasNext()) { DatabaseField field = (DatabaseField)it.next(); session.getIntegrityChecker().handleError(DescriptorException.customQueryAndReturningPolicyFieldConflict(field.getName(), queryTypeName[operation], getDescriptor())); } } } } } } /** * INTERNAL: * Returns an equal field held by ReturningPolicy, or null. */ public DatabaseField getField(DatabaseField field) { DatabaseField foundField = null; if (this.fieldsNotFromDescriptor_DefaultTable != null) { foundField = this.fieldsNotFromDescriptor_DefaultTable.get(field); } if ((foundField == null) && (this.fieldsNotFromDescriptor_OtherTables != null)) { foundField = this.fieldsNotFromDescriptor_OtherTables.get(field); } return foundField; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy