use of org.eclipse.persistence.sdo.helper.ListWrapper in project eclipselink by eclipse-ee4j.
the class SDODataObject method undoChanges.
/**
* INTERNAL:
* This function reverses any operations that were performed on this object since change tracking
* was turned on. The object is returned to the state when logging was first started.<br>
* @param isCSRoot
* @param cs
* @param origContainer
* @param origContainmentPropName
*/
public //
void undoChanges(//
boolean isCSRoot, //
ChangeSummary cs, SDODataObject origContainer, String origContainmentPropName) {
// dont do anything if the changeSummary is null
if (null == cs) {
return;
}
// base step: swap valueStores at the current node
if (((SDOChangeSummary) cs).isDirty(this)) {
// reset only if changes were done
if (!isCSRoot) {
// reset changeSummary
if (null == changeSummary) {
// we are not recursively setting cs - so don't use the set function as child nodes will be replaced later
changeSummary = (SDOChangeSummary) cs;
}
// reset container
if (null == container) {
_setContainer(origContainer);
}
// reset containmentProperty name
if (null == containmentPropertyName) {
_setContainmentPropertyName(origContainmentPropName);
}
}
// swap valueStores
_setCurrentValueStore((ValueStore) ((SDOChangeSummary) cs).getOriginalValueStores().get(this));
// return original to null (no changes)
((SDOChangeSummary) cs).getOriginalValueStores().remove(this);
}
// swap sequences (may be UC2(DataObject and sequence change) or UC4 (sequence change only)
if (getType().isSequenced()) {
// perform sequence.isDirty check independent of a dataObject.isDirty check
if (((SDOChangeSummary) cs).isDirty(sequence)) {
Sequence currentSequence = sequence;
SDOSequence originalSequence = (SDOSequence) ((SDOChangeSummary) cs).getOriginalSequences().get(this);
// both sequences are either null or set
if ((null == originalSequence) && (null != currentSequence)) {
throw SDOException.oldSequenceNotFound();
} else {
sequence = originalSequence;
}
// reset the cache map
((SDOChangeSummary) cs).getOldSequences().remove(this);
// rest the primary map
((SDOChangeSummary) cs).getOriginalSequences().remove(this);
}
}
// restore any open content properties to the 3 data structures on SDODataObject, and remove from cs.unsetOCPropsMap
// see openContentPropertiesMap<String,Property>, openContentProperties(List<Property>). instanceProperties (List<Property>)
List oldUnsetOCList = ((SDOChangeSummary) cs).getUnsetOCProperties(this);
for (int i = 0, size = oldUnsetOCList.size(); i < size; i++) {
// it is essential that the oc property is removed from the cs or we will get an unsupported op during resetChanges()
// the property will be added only when logging=true, we reference the first item in the list as it reduces in size
addOpenContentProperty((Property) oldUnsetOCList.get(0));
}
// recursive step: swap valueStores on every contained subtree
for (Iterator iterProperties = getInstanceProperties().iterator(); iterProperties.hasNext(); ) {
SDOProperty property = (SDOProperty) iterProperties.next();
if (!property.getType().isChangeSummaryType()) {
Object value = get(property);
if ((null == value) && (null != getChangeSummary())) {
// no changes for null properties
} else {
if (property.isMany()) {
// assumption that we never have a null ListWrapper should still avoid a possible NPE
if (null != value) {
((ListWrapper) value).undoChanges(getChangeSummary());
if (!property.getType().isDataType()) {
for (Iterator iterMany = ((List) value).iterator(); iterMany.hasNext(); ) {
Object valueMany = iterMany.next();
if (null != valueMany) {
// handle micro-corner case ListWrapper is null
((SDODataObject) valueMany).undoChanges(false, changeSummary, this, property.getName());
}
}
}
}
} else {
if (!property.getType().isDataType() && (null != value)) {
((SDODataObject) value).undoChanges(false, changeSummary, this, property.getName());
}
}
}
}
}
}
use of org.eclipse.persistence.sdo.helper.ListWrapper in project eclipselink by eclipse-ee4j.
the class SDODataObject method setInternal.
public void setInternal(SDOProperty property, Object value, boolean updateSequence) throws UnsupportedOperationException, IllegalArgumentException {
if (null == getType()) {
throw new UnsupportedOperationException("Type is null");
}
if (property.isOpenContent() && !getType().isOpen()) {
// not open and not in types currentValueStore
throw new IllegalArgumentException("DataObject " + this + " is not Open for property " + property.getName());
}
// Note: get() will call setPropertyInternal() if the list is null = not set yet - we need to propagate the updateSequence flag
Object oldValue = get(property);
boolean wasSet = isSet(property);
if (wasSet && (oldValue == value)) {
return;
} else {
_setModified(true);
}
if (property.isMany()) {
List listValue;
if (null == value) {
listValue = new ListWrapper(this, property);
} else {
try {
listValue = (List) value;
} catch (ClassCastException e) {
throw new IllegalArgumentException("Properties with isMany = true can only be set on list values.");
}
}
if (property.isContainment() || isContainedByDataGraph(property)) {
for (Object next : listValue) {
if (next instanceof SDODataObject) {
if (parentContains(next)) {
throw new IllegalArgumentException("Circular reference.");
}
}
}
}
ListWrapper oldValueListWrapper = (ListWrapper) oldValue;
// 20060529: v33: Move clear() out of ListWrapper.addAll()
// handle clearing of elements which also calls removeContainment(prop) outside of addAll()
oldValueListWrapper.clear(updateSequence);
// handle updateContainment and sequences inside addAll()
// for non-default Pluggable impl this function is not required
oldValueListWrapper.addAll((Collection) value, updateSequence);
} else {
if (property.isContainment() || isContainedByDataGraph(property)) {
if (parentContains(value)) {
throw new IllegalArgumentException("Circular reference.");
}
// detach the oldValue from this dataObject
if (null != oldValue) {
detach(property, oldValue);
}
// sets the new value's container and containment prop to this dataobject, detaches from other owner...not right
/**
* Case: set(do) is actually a move(do) between two CS - detach required
* Case: set(do) is actually an add(do) on a single CS - detach not required
*/
SDODataObject dataObjectValue = (SDODataObject) value;
if (dataObjectValue != null) {
updateContainment(property, dataObjectValue);
}
}
// process pluggable currentValueStore and set [value] as a property of [this] as well as sequences
setPropertyInternal(property, value, updateSequence);
}
if (getType().isOpen() && property.isOpenContent()) {
addOpenContentProperty(property);
}
}
use of org.eclipse.persistence.sdo.helper.ListWrapper in project eclipselink by eclipse-ee4j.
the class SDODataObject method updateDataGraph.
/**
* INTERNAL:
* Recursively set this DataObject's DataGraph
* This function serves as a copy of updateChangeSummaryAndDataGraph() to recursively walk and set the dataGraph.
* that will be run when no recursion occurs in the case that an object (with a changeSummary)
* is set internally to a tree (without a changeSummary).
* Callers: Typically updateContainment (during a set) or delete/detach
* when the current object is internal with its own changeSummary property.
* @param aDataGraph
*/
private void updateDataGraph(DataGraph aDataGraph) {
Iterator iterProperties = getInstanceProperties().iterator();
Property property;
Object object;
Object listContainedObject;
// Add back pointer to containing DataGraph - in preOrder sequence before recursing
setDataGraph(aDataGraph);
// Recurse currentValueStore
while (iterProperties.hasNext()) {
property = (Property) iterProperties.next();
// do not recurse bidirectional currentValueStore that are non-containment
if (property.isContainment() || isContainedByDataGraph(property)) {
object = get(property);
if (object instanceof SDODataObject) {
// DataObject child of this DataObject
((SDODataObject) object).updateDataGraph(aDataGraph);
}
if (object instanceof ListWrapper) {
// ListWrapper child of this DataObject
Iterator anIterator = ((ListWrapper) object).iterator();
while (anIterator.hasNext()) {
listContainedObject = anIterator.next();
if (listContainedObject instanceof SDODataObject) {
((SDODataObject) listContainedObject).updateDataGraph(aDataGraph);
}
}
}
}
}
}
use of org.eclipse.persistence.sdo.helper.ListWrapper in project eclipselink by eclipse-ee4j.
the class SDODataObject method detach.
/**
* INTERNAL:
* Removes this DataObject from its container, if any.
* Same as
* getContainer().getList(getContainmentProperty()).remove(this) or
* getContainer().unset(getContainmentProperty())
* depending on getContainmentProperty().isMany() respectively.
* @param fromDelete (true = delete action, false = detach/unset)
* @param updateSequence
*/
private void detach(boolean fromDelete, boolean updateSequence) {
// Note: there is no case10 where fromDelete=true and updateSequence=false
SDOProperty containmentProperty = getContainmentProperty();
if ((containmentProperty != null) && containmentProperty.isReadOnly()) {
throw new UnsupportedOperationException("Property is Readonly." + containmentProperty.getName() + " " + getType().getName());
}
if (containmentProperty != null) {
if (getContainmentProperty().isMany()) {
List oldList = getContainer().getList(containmentProperty);
// pass remove containment flag instead of calling remove(this) and detachOrDelete(fromDelete) separately
// This will invoke creation of an intact list copy before removing its containment and clearing its changeSummary
((ListWrapper) oldList).remove(this, fromDelete, updateSequence);
} else {
getContainer().unset(containmentProperty, fromDelete, updateSequence);
}
} else {
_setDeleted(true);
detachOrDelete(fromDelete);
}
}
use of org.eclipse.persistence.sdo.helper.ListWrapper in project eclipselink by eclipse-ee4j.
the class SDODataObject method updateContainment.
/**
* INTERNAL:
* Update containment on the dataObject with specified update sequence state
* @param property
* @param aDataObject
* @param updateSequence
*/
public void updateContainment(Property property, SDODataObject aDataObject, boolean updateSequence) {
if (property.isContainment() || isContainedByDataGraph(property)) {
boolean wasInNewCS = //
(getChangeSummary() != null) && (aDataObject.getChangeSummary() != null) && getChangeSummary().equals(aDataObject.getChangeSummary());
// Remove property or old changeSummary
if (aDataObject.getContainer() != null) {
aDataObject.detach(false, updateSequence);
}
// Need to know if the DO was deleted and being re-added later on in this method.
// Since getChangeSummary().isDeleted() will be affected before the code in question
// is hit, store the value now.
boolean isDeleted = false;
if (getChangeSummary() != null) {
isDeleted = getChangeSummary().isDeleted(aDataObject);
}
/**
* The following 2 update functions are kept separate for performance reasons in #6473342..
* Alternate implementations could have used a Command pattern object or boolean states to enable a
* single function to perform multiple operations.
*
* The DataGraph pointer on all subtrees are always updated regardless of the dataGraph value.
* However, the ChangeSummary pointer is only updated if the dataObject(value) being updated is not
* itself an internal changeSummary root.
* For example: the following would not update the CS to null when we get to dataObject B - as it has its own changeSummary-B
* root
* -> B
* -> CS-B
* -> D (String)
* But, the following would update the CS to CS-root when we get to dataObject B because the changeSummary root is above it
* root
* -> B
* -> D (String)
* -> CS-root
*/
if (//
(getChangeSummary() != null) && (aDataObject.getType() != null) && (aDataObject.getType().getChangeSummaryProperty() == null)) {
// Recursively set the current changeSummary and dataGraph - the CS root is above or absent
aDataObject.updateChangeSummaryAndDataGraph(getChangeSummary(), getDataGraph());
} else {
// Recursively set the dataGraph when this level (value) is the CS root n the subtree
if (aDataObject.getDataGraph() != getDataGraph()) {
aDataObject.updateDataGraph(getDataGraph());
}
}
// add value as a property of (this)
aDataObject._setContainer(this);
aDataObject._setContainmentPropertyName(property.getName());
// We don't setCreated for objects that were previously deleted
if (!wasInNewCS && (getChangeSummary() != null) && !getChangeSummary().isDeleted(aDataObject)) {
aDataObject._setCreated(true);
}
// so we end up with all isDeleted, isModified == false
if ((getChangeSummary() != null) && getChangeSummary().isDeleted(aDataObject)) {
// explicitly clear the oldSetting and clear the key:value pair in the deleted map
aDataObject._setDeleted(false);
// remove oldSetting from map only when we return to original position
// by comparing an undo() with the projected model after set() - for now keep oldSettings
}
// modify container object
_setModified(true);
// the change summary's OriginalValueStores list to ensure isModified correctness
if (isDeleted) {
// May need to remove the corresponding entry in the originalValueStore map.
// Compare the value store to the corresponding entry in the originalValueStore map.
// Check to see if we're adding into the old parent (undo delete) or into a new parent (move)
Map originalValueStores = getChangeSummary().getOriginalValueStores();
ValueStore originalVS = ((ValueStore) originalValueStores.get(aDataObject));
if (originalVS.equals(aDataObject._getCurrentValueStore())) {
// Remove the old value store from the change summary
originalValueStores.remove(aDataObject);
}
DataObject oldParentDO = getChangeSummary().getOldContainer(aDataObject);
if (oldParentDO == this) {
// The data object was deleted and is now being re-added to same parent object.
// May need to remove the corresponding entry in the oldValueStore map.
// Compare the parent value store to the corresponding entry in the oldValueStore map.
ValueStore originalParentVS = ((ValueStore) originalValueStores.get(oldParentDO));
if (originalParentVS.equals(this._getCurrentValueStore())) {
// Value stores are equal, now make sure no ListWrappers have been modified
// For each typePropertyValue that is a ListWrapper in the currentValueStore, check
// the OriginalElements list in the CS to see if that wrapper exists in the list (indicating
// the wrapper's list was modified at some point) and if it does, compare the current list
// to that original list. If they are equal, and the value stores are equal, the entries
// can be removed from the change summary so isModified will work correctly
Object prop;
Object oldList;
Map originalElements = getChangeSummary().getOriginalElements();
List oldParentProps = oldParentDO.getInstanceProperties();
for (int i = 0; i < oldParentProps.size(); i++) {
prop = originalParentVS.getDeclaredProperty(i);
oldList = originalElements.get(prop);
if (oldList != null) {
List oldElements = (List) oldList;
List currentElements = ((ListWrapper) prop).getCurrentElements();
if (oldElements.size() != currentElements.size()) {
// A ListWrapper has been modified - don't remove the old value store entry
return;
}
Iterator elementIt = currentElements.iterator();
Iterator oldelementIt = oldElements.iterator();
while (elementIt.hasNext()) {
if (elementIt.next() != oldelementIt.next()) {
// A ListWrapper has been modified - don't remove the old value store entry
return;
}
}
}
}
// Remove the old value store from the change summary
originalValueStores.remove(oldParentDO);
}
}
}
}
}
Aggregations