org.eclipse.persistence.sdo.helper.SDOUnmarshalListener 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 180e602
/*******************************************************************************
* Copyright (c) 1998, 2012 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 v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.sdo.helper;
import commonj.sdo.DataObject;
import commonj.sdo.Property;
import commonj.sdo.Sequence;
import commonj.sdo.helper.HelperContext;
import commonj.sdo.helper.TypeHelper;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.persistence.sdo.SDOChangeSummary;
import org.eclipse.persistence.sdo.SDOConstants;
import org.eclipse.persistence.sdo.SDODataObject;
import org.eclipse.persistence.sdo.SDOProperty;
import org.eclipse.persistence.sdo.SDOSequence;
import org.eclipse.persistence.exceptions.SDOException;
import org.eclipse.persistence.internal.oxm.XMLConversionManager;
import org.eclipse.persistence.oxm.XMLRoot;
import org.eclipse.persistence.oxm.XMLUnmarshaller;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* Purpose: Implementation of XMLUnmarshalListener used when unmarshalling XML to XMLDocuments
*
Responsibilities:
* - When creating a DataObject we need to call setType and setHelperContext with the appropriate values
*
- When we are finished Unmarshalling the root object we need to set up the ChangeSummary objects.
* ChangeSummaries have xpaths to other parts of the documents so the rest of the objects need to be built before we process the ChangeSummaries
*
*/
public class SDOUnmarshalListener extends SDOCSUnmarshalListener {
private List changeSummaries;
public SDOUnmarshalListener(HelperContext aContext) {
super(aContext);
}
public void beforeUnmarshal(Object target, Object parent) {
//Setting the helperContext and type on the DataObject or ChangeSummary
super.beforeUnmarshal(target, parent);
}
/**
* @param target assumed to be non-null
* @param parent may be null, indicating target is root object
*/
public void afterUnmarshal(Object target, Object parent) {
SDODataObject targetDataObject;
// assume target is DataObject or ChangeSummary
try {
targetDataObject = (SDODataObject)target;
} catch (ClassCastException ccex) {
// each time we hit a ChangeSummary store it to process later and set its root
// object - this is because we can't fully process the cs's because they have
// references that can't be resolved until the full tree is built
SDOChangeSummary sdoChangeSummary = (SDOChangeSummary) target;
sdoChangeSummary.setRootDataObject((DataObject)parent);
getChangeSummaries().add(sdoChangeSummary);
return;
}
// if getType is sequenced, then update values to settings map
if (targetDataObject.getType().isSequenced()) {
targetDataObject.getSequence().afterUnmarshal();
}
// if parent is null we are back to the root object
// the last object that will hit the afterUnmarshal method
if (parent == null && null != changeSummaries) {
XMLUnmarshaller unmarshaller = null;
for (int i = 0, changeSummariesSize=changeSummaries.size(); i < changeSummariesSize; i++) {
SDOChangeSummary nextCS = changeSummaries.get(i);
// Set logging to true until finished building modified list.
boolean loggingValue = nextCS.isLoggingMapping();
nextCS.setLogging(true);
// CREATES
// For each xpath in the create attribute convert it to an sdo path and execute it against the root
// dataobject to get the dataobject being pointed to and set that dataobject to be created
List xpaths = nextCS.getCreatedXPaths();
for (int j = 0, xpathsSize = xpaths.size(); j < xpathsSize; j++) {
String nextXPath = (String)xpaths.get(j);
String sdoPath = convertXPathToSDOPath(nextXPath);
SDODataObject nextCreatedDO = targetDataObject.getDataObject(sdoPath);
if(nextCreatedDO == null) {
int nextSlash = sdoPath.indexOf('/');
if(nextSlash != -1) {
sdoPath = sdoPath.substring(nextSlash + 1);
} else {
sdoPath = "/";
}
nextCreatedDO = targetDataObject.getDataObject(sdoPath);
}
if (nextCreatedDO != null) {
nextCreatedDO._setCreated(true);
nextCS.getOldContainers().remove(nextCreatedDO);
} else {
throw SDOException.errorProcessingXPath(nextXPath);
}
}
//clear the createxpaths list that was read in from XML
nextCS.setCreatedXPaths(null);
//MODIFIED
List modifiedDoms = nextCS.getModifiedDoms();
for (int j = 0, modifiedDomsSize=modifiedDoms.size(); j < modifiedDomsSize; j++) {
Element nextNode = (Element)modifiedDoms.get(j);
String refValue = nextNode.getAttributeNS(SDOConstants.SDO_URL, SDOConstants.CHANGESUMMARY_REF);
if ((refValue == null) || (refValue.length() == 0)) {
throw SDOException.missingRefAttribute();
}
//nextModifiedDO is the real modified current data object
String sdoPath = convertXPathToSDOPath(refValue);
SDODataObject nextModifiedDO = targetDataObject.getDataObject(sdoPath);
//if it failed, try peeling off the first fragment (may be the root
if(nextModifiedDO == null) {
int nextSlash = sdoPath.indexOf('/');
if(nextSlash != -1) {
sdoPath = sdoPath.substring(nextSlash + 1);
} else {
sdoPath = "/";
}
nextModifiedDO = targetDataObject.getDataObject(sdoPath);
}
String unsetValue = nextNode.getAttributeNS(SDOConstants.SDO_URL, SDOConstants.CHANGESUMMARY_UNSET);
List unsetValueList = new ArrayList();
if ((unsetValue != null) && (unsetValue.length() > 0)) {
XMLConversionManager xmlConversionManager = ((SDOXMLHelper) aHelperContext.getXMLHelper()).getXmlConversionManager();
unsetValueList = (List)xmlConversionManager.convertObject(unsetValue, List.class);
}
if (nextModifiedDO != null) {
nextModifiedDO._setModified(true);
SDOCSUnmarshalListener listener = new SDOCSUnmarshalListener(nextModifiedDO.getType().getHelperContext(), true);
if(null == unmarshaller) {
unmarshaller = ((SDOXMLHelper)aHelperContext.getXMLHelper()).getXmlContext().createUnmarshaller();
}
unmarshaller.setUnmarshalListener(listener);
unmarshaller.getProperties().put("sdoHelperContext", aHelperContext);
unmarshaller.setUnmappedContentHandlerClass(SDOUnmappedContentHandler.class);
Object unmarshalledNode = unmarshaller.unmarshal(nextNode, nextModifiedDO.getType().getXmlDescriptor().getJavaClass());
//unmarshalledDO is the modified dataobject from the changesummary xml
SDODataObject unmarshalledDO = null;
// Assumption: unmarshalledNode should always be either an instance of XMLRoot or DataObject
if (unmarshalledNode instanceof XMLRoot) {
unmarshalledDO = (SDODataObject)((XMLRoot)unmarshalledNode).getObject();
} else if (unmarshalledNode instanceof DataObject) {
unmarshalledDO = (SDODataObject)unmarshalledNode;
}
List modifiedProps = new ArrayList();
Node n = nextNode.getFirstChild();
TypeHelper typeHelper = aHelperContext.getTypeHelper();
while(n != null) {
if (n.getNodeType() == Node.ELEMENT_NODE) {
String propName = n.getLocalName();
Property nextProp = unmarshalledDO.getInstanceProperty(propName);
if (nextProp == null) {
nextProp = typeHelper.getOpenContentProperty(n.getNamespaceURI(), propName);
}
if (!modifiedProps.contains(nextProp)) {
modifiedProps.add(nextProp);
}
}
n = n.getNextSibling();
}
//instead of iterating over all props can we just check elements in cs and get appropriate properties from DO
for (int k = 0, modifiedPropsSize = modifiedProps.size(); k < modifiedPropsSize; k++) {
SDOProperty nextProp = (SDOProperty)modifiedProps.get(k);
if (!nextProp.getType().isDataType()) {
if (nextProp.isMany()) {
//original value is the list from the changesummary xml
List originalValue = unmarshalledDO.getList(nextProp);
List newList = new ArrayList();
List toDelete = new ArrayList();
List indexsToDelete = new ArrayList();
for (int l = 0, originalValueSize = originalValue.size(); l < originalValueSize; l++) {
SDODataObject nextInList = (SDODataObject)originalValue.get(l);
String sdoRef = nextInList._getSdoRef();
if (sdoRef != null) {
//if sdoRef is not null then object is modified
String sdoRefPath = convertXPathToSDOPath(sdoRef);
int nextSlash = sdoRefPath.indexOf('/');
if(nextSlash != -1) {
sdoRefPath = sdoRefPath.substring(nextSlash + 1);
} else {
sdoRefPath = "/";
}
newList.add(targetDataObject.getDataObject(sdoRefPath));
} else {
//if sdo ref is null there is a deleted object
toDelete.add(nextInList);
indexsToDelete.add(l);
newList.add(nextInList);
}
}
//lw is the list from the real current data object
ListWrapper lw = ((ListWrapper)nextModifiedDO.getList(nextProp));
int indexsToDeleteSize = indexsToDelete.size();
if (indexsToDeleteSize > 0) {
//after this loop, lw will have the entire list when logging was turned on
nextCS.pauseLogging();
for (int m = 0; m < indexsToDeleteSize; m++) {
int toDeleteIndex = ((Integer)indexsToDelete.get(m)).intValue();
SDODataObject nextToDelete = (SDODataObject)toDelete.get(m);
lw.add(toDeleteIndex, nextToDelete);
}
nextCS.setPropertyInternal(nextModifiedDO, nextProp, lw);
SDOSequence nextSeq = ((SDOSequence)nextCS.getOriginalSequences().get(nextModifiedDO));
nextCS.resumeLogging();
nextModifiedDO._setModified(true);
for (int m = indexsToDeleteSize - 1; m >= 0; m--) {
int toDeleteIndex = ((Integer)indexsToDelete.get(m)).intValue();
SDODataObject nextToDelete = (SDODataObject)toDelete.get(m);
if(nextSeq != null){
nextSeq.addSettingWithoutModifyingDataObject(-1, nextProp, nextToDelete);
}
nextToDelete.resetChanges();
lw.remove(toDeleteIndex);
}
}
nextCS.getOriginalElements().put(lw, newList);
} else {
SDODataObject value = unmarshalledDO.getDataObject(nextProp);
if (value != null) {
String sdoRef = value._getSdoRef();
if (sdoRef != null) {
//modified
nextModifiedDO._setModified(true);
} else {
//deleted
value._setChangeSummary(nextCS);
nextModifiedDO._setModified(true);
nextCS.pauseLogging();
boolean wasSet = nextModifiedDO.isSet(nextProp);
Object existingValue = nextModifiedDO.get(nextProp);
// grab index of nextProp's Setting for use during setting below
Sequence nextModifiedDOSequence = nextModifiedDO.getSequence();
int settingIdx = -1;
if (nextModifiedDOSequence != null) {
settingIdx = ((SDOSequence)nextModifiedDOSequence).getIndexForProperty(nextProp);
}
value._setContainmentPropertyName(null);
value._setContainer(null);
nextModifiedDO.set(nextProp, value);
nextCS.setPropertyInternal(nextModifiedDO, nextProp, value);
SDOSequence nextSeq = ((SDOSequence)nextCS.getOriginalSequences().get(nextModifiedDO));
if(nextSeq != null){
nextSeq.addSettingWithoutModifyingDataObject(-1, nextProp, value);
}
nextCS.resumeLogging();
nextModifiedDO._setModified(true);
value.resetChanges();
value.delete();
if (wasSet) {
// need to add at the right pos in the list, not at the end
nextModifiedDO.set(nextProp, existingValue, false);
if (settingIdx != -1) {
nextModifiedDO.getSequence().addSettingWithoutModifyingDataObject(settingIdx, nextProp, existingValue);
}
} else {
nextModifiedDO.unset(nextProp);
}
}
} else {
nextModifiedDO._setModified(true);
nextCS.setPropertyInternal(nextModifiedDO, nextProp, null);
}
}
} else {
nextModifiedDO._setModified(true);
Object value = unmarshalledDO.get(nextProp);
//lw is the list from the real current data object
if(nextProp.isMany()){
Property theProp = nextModifiedDO.getInstanceProperty(nextProp.getName());
if(theProp == null){
Property newProp = nextModifiedDO.defineOpenContentProperty(nextProp.getName(), new ArrayList(), nextProp.getType());
nextModifiedDO.set(newProp, new ArrayList());
theProp = newProp;
}
List lw = nextModifiedDO.getList(theProp.getName());
nextCS.setPropertyInternal(nextModifiedDO, theProp, lw);
nextCS.getOriginalElements().put(lw, ((ListWrapper)value).getCurrentElements());
}else{
nextCS.setPropertyInternal(nextModifiedDO, nextProp, value);
}
}
}
for (int k = 0, unsetValueListSize = unsetValueList.size(); k < unsetValueListSize; k++) {
SDOProperty nextProp = unmarshalledDO.getInstanceProperty((String)unsetValueList.get(k));
if (nextProp != null) {
Object oldValue = null;
if (nextProp.getType().isDataType() || nextProp.isMany()) {
//to get default
oldValue = unmarshalledDO.get(nextProp);
}
nextModifiedDO._setModified(true);
nextCS.setPropertyInternal(nextModifiedDO, nextProp, oldValue);
nextCS.unsetPropertyInternal(nextModifiedDO, nextProp);
} else {
nextProp = nextModifiedDO.getInstanceProperty((String)unsetValueList.get(k));
nextModifiedDO._setModified(true);
nextCS.setPropertyInternal(nextModifiedDO, nextProp, null);
nextCS.unsetPropertyInternal(nextModifiedDO, nextProp);
}
}
} else {
throw SDOException.errorProcessingXPath(refValue);
}
}
//clear modified doms list
nextCS.setModifiedDoms(null);
//clear deleted xpaths list
nextCS.setDeletedXPaths(null);
List created = nextCS.getCreated();
for(int j=0, createdSize = created.size(); j getChangeSummaries() {
if(null == changeSummaries) {
changeSummaries = new ArrayList();
}
return changeSummaries;
}
private String convertXPathToSDOPath(String xpath) {
if ((xpath == null) || (xpath.length() < SDOConstants.SDO_CHANGESUMMARY_REF_PATH_PREFIX_LENGTH) ||//
!xpath.startsWith(SDOConstants.SDO_CHANGESUMMARY_REF_PATH_PREFIX)) {
throw SDOException.errorProcessingXPath(xpath);
}
if (xpath.equals("#/")) {
return "/";
} else if (xpath.startsWith("#/")) {
return xpath.substring(2, xpath.length());
} else {
// remove the sdo ref prefix only "#", leave the root path identifier "/"
return xpath.substring(1, xpath.length());
}
}
}