/** * Merge changes from the source to the target object. Make the necessary removals and adds and * map key modifications. */ private void mergeChangesIntoObjectWithoutOrder( Object target, ChangeRecord changeRecord, Object source, MergeManager mergeManager) { EISCollectionChangeRecord sdkChangeRecord = (EISCollectionChangeRecord) changeRecord; ContainerPolicy cp = this.getContainerPolicy(); AbstractSession session = mergeManager.getSession(); Object targetCollection = null; if (sdkChangeRecord.getOwner().isNew()) { targetCollection = cp.containerInstance(sdkChangeRecord.getAdds().size()); } else { targetCollection = this.getRealCollectionAttributeValueFromObject(target, session); } Vector removes = sdkChangeRecord.getRemoves(); Vector adds = sdkChangeRecord.getAdds(); Vector changedMapKeys = sdkChangeRecord.getChangedMapKeys(); synchronized (targetCollection) { for (Enumeration stream = removes.elements(); stream.hasMoreElements(); ) { Object removeElement = this.buildRemovedElementFromChangeSet(stream.nextElement(), mergeManager); Object targetElement = null; for (Object iter = cp.iteratorFor(targetCollection); cp.hasNext(iter); ) { targetElement = cp.next(iter, session); if (this.compareElements(targetElement, removeElement, session)) { break; // matching element found - skip the rest of them } } if (targetElement != null) { // a matching element was found, remove it cp.removeFrom(targetElement, targetCollection, session); } } for (Enumeration stream = adds.elements(); stream.hasMoreElements(); ) { Object addElement = this.buildAddedElementFromChangeSet(stream.nextElement(), mergeManager); cp.addInto(addElement, targetCollection, session); } for (Enumeration stream = changedMapKeys.elements(); stream.hasMoreElements(); ) { Object changedMapKeyElement = this.buildAddedElementFromChangeSet(stream.nextElement(), mergeManager); Object originalElement = ((UnitOfWorkImpl) session).getOriginalVersionOfObject(changedMapKeyElement); cp.removeFrom(originalElement, targetCollection, session); cp.addInto(changedMapKeyElement, targetCollection, session); } } // reset the attribute to allow for set method to re-morph changes if the collection is not // being stored directly this.setRealAttributeValueInObject(target, targetCollection); }
/** * INTERNAL: Merge changes from the source to the target object. Simply replace the entire target * collection. */ public void mergeIntoObject( Object target, boolean isTargetUnInitialized, Object source, MergeManager mergeManager) { ContainerPolicy cp = this.getContainerPolicy(); AbstractSession session = mergeManager.getSession(); Object sourceCollection = this.getRealCollectionAttributeValueFromObject(source, session); Object targetCollection = cp.containerInstance(cp.sizeFor(sourceCollection)); for (Object iter = cp.iteratorFor(sourceCollection); cp.hasNext(iter); ) { Object targetElement = this.buildElementFromElement(cp.next(iter, session), mergeManager); cp.addInto(targetElement, targetCollection, session); } // reset the attribute to allow for set method to re-morph changes if the collection is not // being stored directly this.setRealAttributeValueInObject(target, targetCollection); }
/** * INTERNAL: The results are *not* in a cursor, build the collection. Cache the results in * temporaryCachedQueryResults. */ protected Object executeNonCursor() throws DatabaseException { Vector rows = getQueryMechanism().executeSelect(); ContainerPolicy containerPolicy = getContainerPolicy(); Object results = null; if (useAbstractRecord) { results = containerPolicy.buildContainerFromVector(rows, getSession()); } else { results = containerPolicy.containerInstance(rows.size()); for (Iterator rowsEnum = rows.iterator(); rowsEnum.hasNext(); ) { containerPolicy.addInto( ((AbstractRecord) rowsEnum.next()).getValues(), results, getSession()); } } // Bug 6135563 - cache DataReadQuery results verbatim, as ObjectBuilder is not invoked cacheResult(results); return results; }
/** * Merge changes from the source to the target object. Simply replace the entire target * collection. */ private void mergeChangesIntoObjectWithOrder( Object target, ChangeRecord changeRecord, Object source, MergeManager mergeManager) { ContainerPolicy cp = this.getContainerPolicy(); AbstractSession session = mergeManager.getSession(); Vector changes = ((EISOrderedCollectionChangeRecord) changeRecord).getNewCollection(); Object targetCollection = cp.containerInstance(changes.size()); for (Enumeration stream = changes.elements(); stream.hasMoreElements(); ) { Object targetElement = this.buildAddedElementFromChangeSet(stream.nextElement(), mergeManager); cp.addInto(targetElement, targetCollection, session); } // reset the attribute to allow for set method to re-morph changes if the collection is not // being stored directly this.setRealAttributeValueInObject(target, targetCollection); }
/** * INTERNAL: Build and return the change record that results from comparing the two collection * attributes. */ public ChangeRecord compareForChange( Object clone, Object backup, ObjectChangeSet owner, AbstractSession session) { ContainerPolicy cp = this.getContainerPolicy(); Object cloneCollection = this.getRealCollectionAttributeValueFromObject(clone, session); Object backupCollection = null; if (owner.isNew()) { backupCollection = cp.containerInstance(1); } else { backupCollection = this.getRealCollectionAttributeValueFromObject(backup, session); } if (cp.hasOrder()) { return this.compareAttributeValuesForChangeWithOrder( cloneCollection, backupCollection, owner, session); } else { return this.compareAttributeValuesForChangeWithoutOrder( cloneCollection, backupCollection, owner, session); } }
/** * INTERNAL: Execute the query. If there are cached results return those. This must override the * super to support result caching. * * @param session - the session in which the receiver will be executed. * @return An object or vector, the result of executing the query. * @exception DatabaseException - an error has occurred on the database */ public Object execute(AbstractSession session, AbstractRecord row) throws DatabaseException { if (shouldCacheQueryResults()) { if (getContainerPolicy().overridesRead()) { throw QueryException.cannotCacheCursorResultsOnQuery(this); } if (shouldConformResultsInUnitOfWork()) { throw QueryException.cannotConformAndCacheQueryResults(this); } if (isPrepared()) { // only prepared queries can have cached results. Object queryResults = getQueryResults(session, row, true); if (queryResults != null) { if (QueryMonitor.shouldMonitor()) { QueryMonitor.incrementReadAllHits(this); } // bug6138532 - check for "cached no results" (InvalidObject singleton) in query // results, and return an empty container instance as configured if (queryResults == InvalidObject.instance) { return getContainerPolicy().containerInstance(0); } Collection results = (Collection) queryResults; if (session.isUnitOfWork()) { ContainerPolicy policy = getContainerPolicy(); Object resultCollection = policy.containerInstance(results.size()); Object iterator = policy.iteratorFor(results); while (policy.hasNext(iterator)) { Object result = ((UnitOfWorkImpl) session) .registerExistingObject(policy.next(iterator, session), this.descriptor); policy.addInto(result, resultCollection, session); } return resultCollection; } return results; } } } if (QueryMonitor.shouldMonitor()) { QueryMonitor.incrementReadAllMisses(this); } return super.execute(session, row); }
/** * INTERNAL: The results are *not* in a cursor, build the collection. Cache the results in * temporaryCachedQueryResults. */ protected Object executeNonCursor() throws DatabaseException { Vector rows = getQueryMechanism().executeSelect(); Object results = null; if (this.resultType == MAP) { results = getContainerPolicy().buildContainerFromVector(rows, this.session); } else if (this.resultType == VALUE) { if (!rows.isEmpty()) { AbstractRecord record = (AbstractRecord) rows.get(0); // Use get with field for XML records. results = record.get(record.getFields().get(0)); if (getValueConverter() != null) { results = getValueConverter().convertDataValueToObjectValue(results, this.session); } } } else { int size = rows.size(); ContainerPolicy containerPolicy = getContainerPolicy(); results = containerPolicy.containerInstance(size); if (containerPolicy.shouldAddAll()) { if (size > 0) { List values = new ArrayList(size); for (int index = 0; index < size; index++) { AbstractRecord row = (AbstractRecord) rows.get(index); Object value = buildObject(row); values.add(value); } containerPolicy.addAll(values, results, this.session, rows, this); } } else { for (int index = 0; index < size; index++) { AbstractRecord row = (AbstractRecord) rows.get(index); Object value = buildObject(row); containerPolicy.addInto(value, results, this.session, row, this); } } } // Bug 6135563 - cache DataReadQuery results verbatim, as ObjectBuilder is not invoked cacheResult(results); return results; }
/** * INTERNAL: All objects queried via a UnitOfWork get registered here. If the query went to the * database. * * <p>Involves registering the query result individually and in totality, and hence refreshing / * conforming is done here. * * @param result may be collection (read all) or an object (read one), or even a cursor. If in * transaction the shared cache will be bypassed, meaning the result may not be originals from * the parent but raw database rows. * @param unitOfWork the unitOfWork the result is being registered in. * @param arguments the original arguments/parameters passed to the query execution. Used by * conforming * @param buildDirectlyFromRows If in transaction must construct a registered result from raw * database rows. * @return the final (conformed, refreshed, wrapped) UnitOfWork query result */ public Object registerResultInUnitOfWork( Object result, UnitOfWorkImpl unitOfWork, AbstractRecord arguments, boolean buildDirectlyFromRows) { // For bug 2612366: Conforming results in UOW extremely slow. // Replacing results with registered versions in the UOW is a part of // conforming and is now done while conforming to maximize performance. if (shouldConformResultsInUnitOfWork() || this.descriptor.shouldAlwaysConformResultsInUnitOfWork()) { return conformResult(result, unitOfWork, arguments, buildDirectlyFromRows); } // When building directly from rows, one of the performance benefits // is that we no longer have to wrap and then unwrap the originals. // result is just a vector, not a collection of wrapped originals. // Also for cursors the initial connection is automatically registered. if (buildDirectlyFromRows) { List<AbstractRecord> rows = (List<AbstractRecord>) result; ContainerPolicy cp = getContainerPolicy(); int size = rows.size(); Object clones = cp.containerInstance(size); for (int index = 0; index < size; index++) { AbstractRecord row = rows.get(index); // null is placed in the row collection for 1-m joining to filter duplicate rows. if (row != null) { Object clone = buildObject(row); cp.addInto(clone, clones, unitOfWork, row, this); } } return clones; } ContainerPolicy cp; Cursor cursor = null; // If the query is redirected then the collection returned might no longer // correspond to the original container policy. CR#2342-S.M. if (getRedirector() != null) { cp = ContainerPolicy.buildPolicyFor(result.getClass()); } else { cp = getContainerPolicy(); } // In the case of cursors just register the initially read collection. if (cp.isCursorPolicy()) { cursor = (Cursor) result; // In nested UnitOfWork session might have been session of the parent. cursor.setSession(unitOfWork); cp = ContainerPolicy.buildPolicyFor(ClassConstants.Vector_class); result = cursor.getObjectCollection(); } Object clones = cp.containerInstance(cp.sizeFor(result)); AbstractSession sessionToUse = unitOfWork.getParent(); for (Object iter = cp.iteratorFor(result); cp.hasNext(iter); ) { Object object = cp.next(iter, sessionToUse); Object clone = registerIndividualResult(object, unitOfWork, this.joinedAttributeManager); cp.addInto(clone, clones, unitOfWork); } if (cursor != null) { cursor.setObjectCollection((Vector) clones); return cursor; } else { return clones; } }
/** INTERNAL: Conform the result if specified. */ protected Object conformResult( Object result, UnitOfWorkImpl unitOfWork, AbstractRecord arguments, boolean buildDirectlyFromRows) { if (getSelectionCriteria() != null) { ExpressionBuilder builder = getSelectionCriteria().getBuilder(); builder.setSession(unitOfWork.getRootSession(null)); builder.setQueryClass(getReferenceClass()); } // If the query is redirected then the collection returned might no longer // correspond to the original container policy. CR#2342-S.M. ContainerPolicy cp; if (getRedirector() != null) { cp = ContainerPolicy.buildPolicyFor(result.getClass()); } else { cp = getContainerPolicy(); } // This code is now a great deal different... For one, registration is done // as part of conforming. Also, this should only be called if one actually // is conforming. // First scan the UnitOfWork for conforming instances. // This will walk through the entire cache of registered objects. // Let p be objects from result not in the cache. // Let c be objects from cache. // Presently p intersect c = empty set, but later p subset c. // By checking cache now doesConform will be called p fewer times. Map indexedInterimResult = unitOfWork.scanForConformingInstances( getSelectionCriteria(), getReferenceClass(), arguments, this); Cursor cursor = null; // In the case of cursors just conform/register the initially read collection. if (cp.isCursorPolicy()) { cursor = (Cursor) result; cp = ContainerPolicy.buildPolicyFor(ClassConstants.Vector_class); // In nested UnitOfWork session might have been session of the parent. cursor.setSession(unitOfWork); result = cursor.getObjectCollection(); // for later incremental conforming... cursor.setInitiallyConformingIndex(indexedInterimResult); cursor.setSelectionCriteriaClone(getSelectionCriteria()); cursor.setTranslationRow(arguments); } // Now conform the result from the database. // Remove any deleted or changed objects that no longer conform. // Deletes will only work for simple queries, queries with or's or anyof's may not return // correct results when untriggered indirection is in the model. Vector fromDatabase = null; // When building directly from rows, one of the performance benefits // is that we no longer have to wrap and then unwrap the originals. // result is just a vector, not a container of wrapped originals. if (buildDirectlyFromRows) { Vector rows = (Vector) result; fromDatabase = new Vector(rows.size()); for (int i = 0; i < rows.size(); i++) { Object object = rows.elementAt(i); // null is placed in the row collection for 1-m joining to filter duplicate rows. if (object != null) { Object clone = conformIndividualResult( object, unitOfWork, arguments, getSelectionCriteria(), indexedInterimResult, buildDirectlyFromRows); if (clone != null) { fromDatabase.addElement(clone); } } } } else { fromDatabase = new Vector(cp.sizeFor(result)); AbstractSession sessionToUse = unitOfWork.getParent(); for (Object iter = cp.iteratorFor(result); cp.hasNext(iter); ) { Object object = cp.next(iter, sessionToUse); Object clone = conformIndividualResult( object, unitOfWork, arguments, getSelectionCriteria(), indexedInterimResult, buildDirectlyFromRows); if (clone != null) { fromDatabase.addElement(clone); } } } // Now add the unwrapped conforming instances into an appropriate container. // Wrapping is done automatically. // Make sure a vector of exactly the right size is returned. Object conformedResult = cp.containerInstance(indexedInterimResult.size() + fromDatabase.size()); Object eachClone; for (Iterator enumtr = indexedInterimResult.values().iterator(); enumtr.hasNext(); ) { eachClone = enumtr.next(); cp.addInto(eachClone, conformedResult, unitOfWork); } for (Enumeration enumtr = fromDatabase.elements(); enumtr.hasMoreElements(); ) { eachClone = enumtr.nextElement(); cp.addInto(eachClone, conformedResult, unitOfWork); } if (cursor != null) { cursor.setObjectCollection((Vector) conformedResult); // For nested UOW must copy all in object collection to // initiallyConformingIndex, as some of these could have been from // the parent UnitOfWork. if (unitOfWork.isNestedUnitOfWork()) { for (Enumeration enumtr = cursor.getObjectCollection().elements(); enumtr.hasMoreElements(); ) { Object clone = enumtr.nextElement(); indexedInterimResult.put(clone, clone); } } return cursor; } else { return conformedResult; } }