package com.webobjects.eoaccess; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSComparator; import com.webobjects.foundation.NSComparator.ComparisonException; import com.webobjects.foundation.NSForwardException; import er.extensions.eof.ERXEntityFKConstraintOrder; import er.extensions.eof.ERXEntityOrder; /** * <p>EODatabaseContext delegate to order adaptor operations by FK constraints. This prevents most ordering * operations on databases like MS SQL that do not support deferred constraints like a real database. * The easiest way to use this is:</p> * <pre> * ERXDatabaseContextMulticastingDelegate.addDefaultDelegate(new ERXEntityDependencyOrderingDelegate()); * </pre> * To turn this on for a Wonder application, just set this property: * <pre> * com.webobjects.eoaccess.ERXEntityDependencyOrderingDelegate.active = true * </pre> * * @author chill */ public class ERXEntityDependencyOrderingDelegate { public static final String ERXEntityDependencyOrderingDelegateActiveKey = "com.webobjects.eoaccess.ERXEntityDependencyOrderingDelegate.active"; protected NSComparator adaptorOpComparator; private static final Logger log = LoggerFactory.getLogger(ERXEntityDependencyOrderingDelegate.class); public ERXEntityDependencyOrderingDelegate() { super(); } /** * Lazy creation of an EOAdaptorOpComparator that uses a list of entities that are in FK dependency order. * Enable DEBUG logging to see the ordered list of entity names. * * @see com.webobjects.eoaccess.EOAdaptorOpComparator * @return EOAdaptorOpComparator that uses a list of entities that are in FK dependency order */ protected NSComparator adaptorOpComparator() { if (adaptorOpComparator == null) { ERXEntityFKConstraintOrder constraintOrder = new ERXEntityFKConstraintOrder(); NSComparator entityOrderingComparator = new ERXEntityOrder.EntityInsertOrderComparator(constraintOrder); try { NSArray<EOEntity> entityOrdering = constraintOrder.allEntities().sortedArrayUsingComparator(entityOrderingComparator); NSArray<String> entityNameOrdering = (NSArray<String>)entityOrdering.valueForKey("name"); if (log.isDebugEnabled()) { log.debug("Entity ordering:\n{}", entityNameOrdering.componentsJoinedByString("\n")); } adaptorOpComparator = new ERXAdaptorOpComparator(entityNameOrdering); } catch (ComparisonException e) { throw NSForwardException._runtimeExceptionForThrowable(e); } } return adaptorOpComparator; } /** * EODatabaseContext.Delegate method to order a list of adaptor operations. Uses adaptorOpComparator() for the ordering. * * @param aDatabaseContext EODatabaseContext that the operations will be executed in * @param adaptorOperations list of operations to execute * @param adaptorChannel the adaptor channel these will be executed on * * @see com.webobjects.eoaccess.EODatabaseContext.Delegate#databaseContextWillPerformAdaptorOperations(EODatabaseContext,NSArray,EOAdaptorChannel) * @return operations in an order that should avoid FK constraint violations */ public NSArray<EOAdaptorOperation> databaseContextWillPerformAdaptorOperations(EODatabaseContext aDatabaseContext, NSArray<EOAdaptorOperation> adaptorOperations, EOAdaptorChannel adaptorChannel) { try { return adaptorOperations.sortedArrayUsingComparator(adaptorOpComparator()); } catch (com.webobjects.foundation.NSComparator.ComparisonException e) { throw NSForwardException._runtimeExceptionForThrowable(e); } } public boolean databaseContextShouldHandleDatabaseException(EODatabaseContext dbCtxt, Throwable exception) { // Useful for debugging if ( ! (exception instanceof EOGeneralAdaptorException)) { log.error("Unexpected non-EOGeneralAdaptorException exception", exception); } return true; } }