| /* |
| * Copyright (c) 1998, 2021 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.sdo; |
| |
| import java.math.BigDecimal; |
| import java.math.BigInteger; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.xml.namespace.QName; |
| |
| import org.eclipse.persistence.exceptions.SDOException; |
| import org.eclipse.persistence.internal.helper.ClassConstants; |
| import org.eclipse.persistence.internal.oxm.XMLConversionManager; |
| import org.eclipse.persistence.oxm.XMLConstants; |
| import org.eclipse.persistence.oxm.XMLRoot; |
| import org.eclipse.persistence.oxm.sequenced.SequencedObject; |
| import org.eclipse.persistence.oxm.sequenced.Setting; |
| import org.eclipse.persistence.sdo.helper.ListWrapper; |
| import org.eclipse.persistence.sdo.helper.SDODataHelper; |
| import org.eclipse.persistence.sdo.helper.SDOTypeHelper; |
| import org.eclipse.persistence.sdo.helper.XPathEngine; |
| |
| import commonj.sdo.ChangeSummary; |
| import commonj.sdo.DataGraph; |
| import commonj.sdo.DataObject; |
| import commonj.sdo.Property; |
| import commonj.sdo.Sequence; |
| import commonj.sdo.Type; |
| import commonj.sdo.helper.DataHelper; |
| import commonj.sdo.helper.HelperContext; |
| |
| public class SDODataObject implements DataObject, SequencedObject { |
| |
| /** |
| * Development Guidelines: |
| * (1) All no-argument get and single argument set functions that are outside the DataObject interface |
| * must be proceeded with a _ underscore in the form _getValue()/_setValue(value). |
| * The reason for this is to avoid naming collisions with generated classes that extend SDODataObject |
| * where the generated get/set methods for POJO fields would collide with the same function here. |
| */ |
| /** The Type that this DataObject represents */ |
| private SDOType type; |
| |
| // t20070714_bc4j: Add pluggable DO support for BC4J using currentValueStore |
| private SDODataObject container; |
| |
| /** |
| * The (currentValueStore) will maintain the current state of our model |
| * after logged changes - it is a shallow copy of the original, progressively becoming deeper with changes. |
| */ |
| private ValueStore currentValueStore; |
| private List openContentProperties; |
| private List openContentPropertiesAttributes; |
| private Map openContentAliasNames; |
| private String containmentPropertyName; |
| private SDOChangeSummary changeSummary; |
| private List<SDOProperty> instanceProperties; |
| private String sdoRef; |
| private SDOSequence sequence; |
| private DataGraph dataGraph; |
| |
| /** hold the current context containing all helpers so that we can preserve inter-helper relationships */ |
| private HelperContext aHelperContext; |
| |
| /**Unique hash ID of this Externalizable class - not required at this point because we serialize the xml representation */ |
| |
| @SuppressWarnings("unused") |
| private String text; |
| |
| //static final long serialVersionUID = 5930094058760264198L; |
| |
| /** |
| * INTERNAL: |
| * Private constructor. |
| * Use {@link org.eclipse.persistence.sdo.helper.delegates.SDODataFactoryDelegate#create(commonj.sdo.Type) SDODataFactoryDelegate.create(Type)} instead |
| */ |
| public SDODataObject() { |
| // Implementors should not be calling this constructor directly - please use SDODataFactory |
| // however if it is called we will initialize the default implementation of the currentValueStore Map |
| // initialize Map Implementation |
| // set currentValueStore Map implementation (replace any that was set in the constructor in newInstance() above) |
| _setCurrentValueStore(new DefaultValueStore()); |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the HelperContext that will be associated with this DataObject. |
| * @param aContext |
| */ |
| public void _setHelperContext(HelperContext aContext) { |
| aHelperContext = aContext; |
| // reset the HelperContext on ChangeSummary |
| if (changeSummary != null) { |
| changeSummary.setHelperContext(aHelperContext); |
| } |
| } |
| |
| @Override |
| public Object get(String path) {// path like "a/b/c" |
| try { |
| return XPathEngine.getInstance().get(path, this); |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return null; |
| } |
| } |
| |
| @Override |
| public void set(String path, Object value) throws ClassCastException, UnsupportedOperationException, IllegalArgumentException { |
| XPathEngine.getInstance().set(path, value, this, false); |
| } |
| |
| @Override |
| public boolean isSet(String path) { |
| return XPathEngine.getInstance().isSet(path, this); |
| } |
| |
| @Override |
| public void unset(String path) { |
| XPathEngine.getInstance().unset(path, this); |
| } |
| |
| @Override |
| public boolean getBoolean(String path) throws ClassCastException { |
| try { |
| Boolean value = (Boolean)XPathEngine.getInstance().convertObjectToValueByPath(path, Boolean.class, this); |
| |
| if (value == null) { |
| return false; |
| } |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return false; |
| } |
| } |
| |
| @Override |
| public byte getByte(String path) { |
| try { |
| Byte value = (Byte)XPathEngine.getInstance().convertObjectToValueByPath(path, Byte.class, this); |
| if (value == null) { |
| return 0; |
| } |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return 0; |
| } |
| } |
| |
| @Override |
| public char getChar(String path) { |
| try { |
| Character value = (Character)XPathEngine.getInstance().convertObjectToValueByPath(path, Character.class, this); |
| if (value == null) { |
| return '\u0000'; |
| } |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return '\u0000'; |
| } |
| } |
| |
| @Override |
| public double getDouble(String path) { |
| try { |
| Double value = (Double)XPathEngine.getInstance().convertObjectToValueByPath(path, Double.class, this); |
| if (value == null) { |
| return 0.0d; |
| } |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return 0.0d; |
| } |
| } |
| |
| @Override |
| public float getFloat(String path) { |
| try { |
| Float value = (Float)XPathEngine.getInstance().convertObjectToValueByPath(path, Float.class, this); |
| if (value == null) { |
| return 0.0f; |
| } |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return 0.0f; |
| } |
| } |
| |
| @Override |
| public int getInt(String path) { |
| try { |
| Integer value = (Integer)XPathEngine.getInstance().convertObjectToValueByPath(path, Integer.class, this); |
| if (value == null) { |
| return 0; |
| } |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return 0; |
| } |
| } |
| |
| @Override |
| public long getLong(String path) { |
| try { |
| Long value = (Long)XPathEngine.getInstance().convertObjectToValueByPath(path, Long.class, this); |
| if (value == null) { |
| return 0L; |
| } |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return 0L; |
| } |
| } |
| |
| @Override |
| public short getShort(String path) { |
| try { |
| Short value = (Short)XPathEngine.getInstance().convertObjectToValueByPath(path, Short.class, this); |
| if (value == null) { |
| return 0; |
| } |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return 0; |
| } |
| } |
| |
| @Override |
| public byte[] getBytes(String path) { |
| try { |
| byte[] value = (byte[])XPathEngine.getInstance().convertObjectToValueByPath(path, byte[].class, this); |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return null; |
| } |
| } |
| |
| @Override |
| public BigDecimal getBigDecimal(String path) { |
| try { |
| BigDecimal value = (BigDecimal)XPathEngine.getInstance().convertObjectToValueByPath(path, BigDecimal.class, this); |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return null; |
| } |
| } |
| |
| @Override |
| public BigInteger getBigInteger(String path) { |
| try { |
| BigInteger value = (BigInteger)XPathEngine.getInstance().convertObjectToValueByPath(path, BigInteger.class, this); |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return null; |
| } |
| } |
| |
| @Override |
| public SDODataObject getDataObject(String path) throws ClassCastException { |
| Object value = get(path); |
| if(value instanceof ListWrapper) { |
| return (SDODataObject)((ListWrapper)value).get(0); |
| } |
| return (SDODataObject)value; |
| } |
| |
| @Override |
| public Date getDate(String path) { |
| try { |
| Date value = (Date)XPathEngine.getInstance().convertObjectToValueByPath(path, Date.class, this); |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return null; |
| } |
| } |
| |
| @Override |
| public String getString(String path) { |
| try { |
| String value = (String)XPathEngine.getInstance().convertObjectToValueByPath(path, String.class, this); |
| return value; |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return null; |
| } |
| } |
| |
| @Override |
| public List getList(String path) { |
| try { |
| return (List)XPathEngine.getInstance().convertObjectToValueByPath(path, List.class, this); |
| } catch (Exception e) { |
| // Swallow exception and return null, as per SDO 2.1 spec |
| return null; |
| } |
| } |
| |
| @Override |
| public void setBoolean(String path, boolean value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setByte(String path, byte value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setChar(String path, char value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setDouble(String path, double value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setFloat(String path, float value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setInt(String path, int value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setLong(String path, long value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setShort(String path, short value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setBytes(String path, byte[] value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setBigDecimal(String path, BigDecimal value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setBigInteger(String path, BigInteger value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setDataObject(String path, DataObject value) { |
| set(path, value); |
| } |
| |
| @Override |
| public void setDate(String path, Date value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setString(String path, String value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public void setList(String path, List value) { |
| convertValueAndSet(path, value); |
| } |
| |
| @Override |
| public Object get(int propertyIndex) throws IllegalArgumentException { |
| Property p = getInstanceProperty(propertyIndex); |
| return get(p); |
| } |
| |
| @Override |
| public void set(int propertyIndex, Object value) { |
| try { |
| Property p = getInstanceProperty(propertyIndex); |
| set(p, value); |
| } catch (IndexOutOfBoundsException e) { |
| throw new IllegalArgumentException("PropertyIndex invalid."); |
| } |
| } |
| |
| @Override |
| public boolean isSet(int propertyIndex) { |
| Property p = getInstanceProperty(propertyIndex); |
| return isSet(p); |
| } |
| |
| @Override |
| public void unset(int propertyIndex) { |
| Property p = getInstanceProperty(propertyIndex); |
| unset(p); |
| } |
| |
| @Override |
| public boolean getBoolean(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getBoolean(property); |
| } |
| |
| @Override |
| public byte getByte(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getByte(property); |
| } |
| |
| @Override |
| public char getChar(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getChar(property); |
| } |
| |
| @Override |
| public double getDouble(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getDouble(property); |
| } |
| |
| @Override |
| public float getFloat(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getFloat(property); |
| } |
| |
| @Override |
| public int getInt(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getInt(property); |
| } |
| |
| @Override |
| public long getLong(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getLong(property); |
| } |
| |
| @Override |
| public short getShort(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getShort(property); |
| } |
| |
| @Override |
| public byte[] getBytes(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getBytes(property); |
| } |
| |
| @Override |
| public BigDecimal getBigDecimal(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getBigDecimal(property); |
| } |
| |
| @Override |
| public BigInteger getBigInteger(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getBigInteger(property); |
| } |
| |
| @Override |
| public SDODataObject getDataObject(int propertyIndex) { |
| Property property = getInstanceProperty(propertyIndex); |
| return getDataObject(property); |
| } |
| |
| @Override |
| public Date getDate(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getDate(property); |
| } |
| |
| @Override |
| public String getString(int propertyIndex) throws IllegalArgumentException, ClassCastException { |
| Property property = getInstanceProperty(propertyIndex); |
| return getString(property); |
| } |
| |
| @Override |
| public List getList(int propertyIndex) { |
| Property property = getInstanceProperty(propertyIndex); |
| return getList(property); |
| } |
| |
| /** |
| * @deprecated in SDO 2.1.0. |
| */ |
| @Deprecated |
| @Override |
| public Sequence getSequence(String path) { |
| // get property from path |
| Object anObject = get(path); |
| |
| if ((null == anObject) || !(anObject instanceof DataObject)) { |
| // throw exception because there is no way to get the property from a null object in this context |
| throw SDOException.sequenceNotFoundForPath(path); |
| } else { |
| // we cannot use containmentProperty in the many case as the index is missing - use the DO |
| return ((DataObject)anObject).getSequence(); |
| } |
| } |
| |
| /** |
| * @deprecated in SDO 2.1.0. |
| */ |
| @Deprecated |
| @Override |
| public Sequence getSequence(int propertyIndex) { |
| // get property |
| Property aProperty = getInstanceProperty(propertyIndex); |
| return getSequencePrivate(aProperty); |
| } |
| |
| /** |
| * @deprecated in SDO 2.1.0. |
| */ |
| @Deprecated |
| @Override |
| public Sequence getSequence(Property property) { |
| return getSequencePrivate(property); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return a Sequence object when the conditions of many=false and dataType=false are met. |
| * Throw an UnsupportedOperationException in all other cases. |
| */ |
| private Sequence getSequencePrivate(Property aProperty) { |
| // we process only complex types that are non-many |
| if ((aProperty != null) && ((SDOProperty)aProperty).getType().isSequenced() && isSet(aProperty) &&// |
| !((SDOProperty)aProperty).getType().isDataType() && !aProperty.isMany()) { |
| return ((DataObject)get(aProperty)).getSequence(); |
| } else { |
| throw SDOException.sequenceNotSupportedForProperty(aProperty.getName()); |
| } |
| } |
| |
| @Override |
| public SDOSequence getSequence() { |
| // sequence object should be null if !sequenced |
| return sequence; |
| } |
| |
| @Override |
| public void setBoolean(int propertyIndex, boolean value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setByte(int propertyIndex, byte value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setChar(int propertyIndex, char value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setDouble(int propertyIndex, double value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setFloat(int propertyIndex, float value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setInt(int propertyIndex, int value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setLong(int propertyIndex, long value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setShort(int propertyIndex, short value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setBytes(int propertyIndex, byte[] value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setBigDecimal(int propertyIndex, BigDecimal value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setBigInteger(int propertyIndex, BigInteger value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setDataObject(int propertyIndex, DataObject value) { |
| set(propertyIndex, value); |
| } |
| |
| @Override |
| public void setDate(int propertyIndex, Date value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setString(int propertyIndex, String value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public void setList(int propertyIndex, List value) { |
| convertValueAndSet(propertyIndex, value); |
| } |
| |
| @Override |
| public Object get(Property property) throws IllegalArgumentException { |
| if (null == property) {// check null property before null type |
| throw new IllegalArgumentException("Argument not Supported."); |
| } |
| |
| if ((null != type) && !type.isOpen() && property.isOpenContent()) { |
| throw new IllegalArgumentException("Argument not Supported."); |
| } |
| if (property.isMany()) { |
| return getList(property); |
| } |
| |
| if (isSet(property)) { |
| return getPropertyInternal(property); |
| } |
| |
| // return the default or a cached pseudo default Object for an unset property |
| // JIRA-253: We are wrapping primitive numerics with a wrapper Object |
| return property.getDefault(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Create a dynamic open content property if no property exists for (name). |
| * @param name |
| * @param value |
| * @return Property |
| * @throws UnsupportedOperationException |
| * @throws IllegalArgumentException |
| */ |
| public Property defineOpenContentProperty(String name, Object value) throws UnsupportedOperationException, IllegalArgumentException { |
| if (value == null) { |
| return null; |
| } |
| DataObject propertyDO = aHelperContext.getDataFactory().create(SDOConstants.SDO_URL, SDOConstants.PROPERTY); |
| |
| propertyDO.set("name", name); |
| Type sdotype = null; |
| boolean isMany = false; |
| boolean isContainment = false; |
| Class valueClass = value.getClass(); |
| |
| if (value instanceof Collection) { |
| if (((Collection)value).size() > 0) { |
| Object firstObject = ((Collection)value).iterator().next(); |
| if (firstObject != null) { |
| valueClass = firstObject.getClass(); |
| if (firstObject instanceof DataObject) { |
| if (((DataObject)firstObject).getContainer() == null) { |
| isContainment = true; |
| } |
| sdotype = ((DataObject)firstObject).getType(); |
| } else { |
| sdotype = ((SDOTypeHelper)aHelperContext.getTypeHelper()).getTypeForSimpleJavaType(valueClass); |
| } |
| } else { |
| return null; |
| } |
| } else { |
| return null; |
| } |
| isMany = true; |
| } else if (value instanceof DataObject) { |
| if (((DataObject)value).getContainer() == null) { |
| isContainment = true; |
| } |
| sdotype = ((DataObject)value).getType(); |
| } else { |
| Property xmlElementProperty = aHelperContext.getTypeHelper().getOpenContentProperty(SDOConstants.SDOXML_URL, SDOConstants.XMLELEMENT_PROPERTY_NAME); |
| propertyDO.set(xmlElementProperty, Boolean.TRUE); |
| sdotype = ((SDOTypeHelper)aHelperContext.getTypeHelper()).getTypeForSimpleJavaType(valueClass); |
| } |
| propertyDO.set("type", sdotype); |
| |
| propertyDO.set("many", isMany); |
| |
| propertyDO.set("containment", isContainment); |
| return aHelperContext.getTypeHelper().defineOpenContentProperty(null, propertyDO); |
| } |
| |
| public Property defineOpenContentProperty(String name, Object value, Type sdotype) throws UnsupportedOperationException, IllegalArgumentException { |
| if (value == null) { |
| return null; |
| } |
| if(sdotype == null){ |
| return defineOpenContentProperty(name, value); |
| } |
| DataObject propertyDO = aHelperContext.getDataFactory().create(SDOConstants.SDO_URL, SDOConstants.PROPERTY); |
| |
| propertyDO.set("name", name); |
| boolean isMany = false; |
| boolean isContainment = false; |
| Class valueClass = value.getClass(); |
| |
| if (value instanceof Collection) { |
| if (((Collection)value).size() > 0) { |
| Object firstObject = ((Collection)value).iterator().next(); |
| if (firstObject != null) { |
| valueClass = firstObject.getClass(); |
| if (firstObject instanceof DataObject) { |
| if (((DataObject)firstObject).getContainer() == null) { |
| isContainment = true; |
| } |
| sdotype = ((DataObject)firstObject).getType(); |
| } else { |
| sdotype = ((SDOTypeHelper)aHelperContext.getTypeHelper()).getTypeForSimpleJavaType(valueClass); |
| } |
| } |
| } |
| isMany = true; |
| } else if (value instanceof DataObject) { |
| if (((DataObject)value).getContainer() == null) { |
| isContainment = true; |
| } |
| sdotype = ((DataObject)value).getType(); |
| } else { |
| sdotype = ((SDOTypeHelper)aHelperContext.getTypeHelper()).getTypeForSimpleJavaType(valueClass); |
| } |
| propertyDO.set("type", sdotype); |
| |
| propertyDO.set("many", isMany); |
| |
| propertyDO.set("containment", isContainment); |
| return aHelperContext.getTypeHelper().defineOpenContentProperty(null, propertyDO); |
| } |
| |
| @Override |
| public void set(Property property, Object value) throws UnsupportedOperationException, IllegalArgumentException { |
| set((SDOProperty) property, value, true); |
| } |
| |
| 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() |
| oldValueListWrapper.addAll((Collection)value, updateSequence);// for non-default Pluggable impl this function is not required |
| } 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); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Sets the value of the given property of the object to the new value. |
| * <p> |
| * The use of a false updateSequence flag is internally implemented during an SDOSequence.add() call. |
| * Refactor: we need to abstract this function using a type of Command pattern to handle the sequence context. |
| * @param property |
| * @param value |
| * @param updateSequence |
| * @throws UnsupportedOperationException |
| * @throws IllegalArgumentException |
| */ |
| public void set(SDOProperty property, Object value, boolean updateSequence) throws UnsupportedOperationException, IllegalArgumentException { |
| if (null == property) { |
| throw new IllegalArgumentException("Illegal Argument."); |
| } |
| |
| if (property.isReadOnly()) { |
| throw new UnsupportedOperationException("Property is Readonly." + property.getName() + " " + getType().getName()); |
| } |
| |
| // Can't set null on a non-nullable property - implementation specific handling, one of: |
| // 1) perform an unset operation |
| // 2) throw new UnsupportedOperationException("Property ["+ property.getName() +"] is non-nullable"); |
| // We will perform an unset op... |
| if (value == null && !property.isNullable()) { |
| unset(property, false, updateSequence); |
| } else { |
| setInternal(property, value, updateSequence); |
| } |
| } |
| |
| @Override |
| public boolean isSet(Property property) { |
| if (null == property) { |
| throw SDOException.cannotPerformOperationOnNullArgument("isSet"); |
| } |
| |
| if (property.isMany()) { |
| List value = getList(property); |
| return !value.isEmpty(); |
| } else { |
| return isSetInternal(property); |
| } |
| } |
| |
| @Override |
| public void unset(Property property) { |
| if (null == property) { |
| throw SDOException.cannotPerformOperationOnNullArgument("unset"); |
| } |
| unset(property, false); |
| } |
| |
| /** |
| * INTERNAL: |
| * This function is implemented internally to unset the specified property on this DataObject |
| * @param property |
| * @param fromDelete |
| */ |
| private void unset(Property property, boolean fromDelete) { |
| unset(property, fromDelete, true); |
| } |
| |
| /** |
| * INTERNAL: |
| * Unset the specified property on this DataObject. |
| * The fromDelete parameter specifies whether we are from a delete or unset/detach operation. |
| * The updateSequence parameter is used internally to stop a bidirectional update in the SDOSequence |
| * when originally called from this Sequence. |
| * @param property |
| * @param fromDelete |
| * @param updateSequence |
| */ |
| public void unset(Property property, boolean fromDelete, boolean updateSequence) { |
| if (null == property) { |
| throw SDOException.cannotPerformOperationOnNullArgument("unset"); |
| } |
| |
| if (property.isReadOnly()) { |
| throw new UnsupportedOperationException("Property is Readonly." + property.getName() + " " + getType().getName()); |
| } |
| |
| boolean wasSet = isSet(property); |
| |
| if (wasSet) { |
| if(!fromDelete){ |
| _setModified(true); |
| } |
| } else { |
| return; |
| } |
| |
| if (property.isContainment() || isContainedByDataGraph(property)) { |
| Object oldValue = get(property); |
| if (oldValue != null) { |
| if (property.isMany()) { |
| for (int itemIndex = 0, size = ((List)oldValue).size(); itemIndex < size; |
| itemIndex++) { |
| SDODataObject manyItem = (SDODataObject)((List)oldValue).get(itemIndex); |
| if (manyItem != null) { |
| manyItem.detachOrDelete(fromDelete); |
| } |
| } |
| } else { |
| ((SDODataObject)oldValue).detachOrDelete(fromDelete); |
| } |
| } |
| } |
| |
| if (wasSet) { |
| unsetInternal(property, updateSequence); |
| } |
| } |
| |
| @Override |
| public boolean getBoolean(Property property) throws IllegalArgumentException, ClassCastException { |
| Boolean propertyBooleanValue = (Boolean)convertObjectToValue(property, Boolean.class); |
| if (propertyBooleanValue == null) { |
| return false; |
| } |
| return propertyBooleanValue; |
| } |
| |
| @Override |
| public byte getByte(Property property) throws IllegalArgumentException, ClassCastException { |
| Byte propertyByteValue = (Byte)convertObjectToValue(property, Byte.class); |
| if (propertyByteValue == null) { |
| return 0; |
| } |
| return propertyByteValue; |
| } |
| |
| @Override |
| public char getChar(Property property) throws IllegalArgumentException { |
| Character propertyCharValue = (Character)convertObjectToValue(property, Character.class); |
| if (propertyCharValue == null) { |
| return '\u0000'; |
| } |
| return propertyCharValue; |
| } |
| |
| @Override |
| public double getDouble(Property property) throws IllegalArgumentException { |
| Double propertyDoubleValue = (Double)convertObjectToValue(property, Double.class); |
| if (propertyDoubleValue == null) { |
| return 0.0d; |
| } |
| return propertyDoubleValue; |
| } |
| |
| @Override |
| public float getFloat(Property property) throws IllegalArgumentException { |
| Float propertyFloatValue = (Float)convertObjectToValue(property, Float.class); |
| if (propertyFloatValue == null) { |
| return 0.0f; |
| } |
| return propertyFloatValue; |
| } |
| |
| @Override |
| public int getInt(Property property) throws IllegalArgumentException { |
| Integer propertyIntegerValue = (Integer)convertObjectToValue(property, Integer.class); |
| if (propertyIntegerValue == null) { |
| return 0; |
| } |
| return propertyIntegerValue; |
| } |
| |
| @Override |
| public long getLong(Property property) throws IllegalArgumentException { |
| Long propertyLongValue = (Long)convertObjectToValue(property, Long.class); |
| if (propertyLongValue == null) { |
| return 0L; |
| } |
| return propertyLongValue; |
| } |
| |
| @Override |
| public short getShort(Property property) throws IllegalArgumentException { |
| Short propertyShortValue = (Short)convertObjectToValue(property, Short.class); |
| if (propertyShortValue == null) { |
| return 0; |
| } |
| return propertyShortValue; |
| } |
| |
| @Override |
| public byte[] getBytes(Property property) throws IllegalArgumentException { |
| byte[] propertyByteValue = (byte[])convertObjectToValue(property, byte[].class); |
| return propertyByteValue; |
| } |
| |
| @Override |
| public BigDecimal getBigDecimal(Property property) throws IllegalArgumentException { |
| BigDecimal propertyDecimalValue = (BigDecimal)convertObjectToValue(property, BigDecimal.class); |
| return propertyDecimalValue; |
| } |
| |
| @Override |
| public BigInteger getBigInteger(Property property) throws IllegalArgumentException { |
| BigInteger propertyBigIntegerValue = (BigInteger)convertObjectToValue(property, BigInteger.class); |
| return propertyBigIntegerValue; |
| } |
| |
| @Override |
| public SDODataObject getDataObject(Property property) throws IllegalArgumentException, ClassCastException { |
| if(property != null && property.isMany()) { |
| List value = (List)get(property); |
| if(value.size() > 0) { |
| return (SDODataObject)value.get(0); |
| } else { |
| return null; |
| } |
| } |
| return (SDODataObject)get(property); |
| } |
| |
| @Override |
| public Date getDate(Property property) { |
| if (null == property) { |
| throw SDOException.cannotPerformOperationOnNullArgument("getDate"); |
| } |
| if (property.getType().equals(SDOConstants.SDO_STRING)) { |
| DataHelper dHelper = aHelperContext.getDataHelper(); |
| String dateString = (String)get(property); |
| return dHelper.toDate(dateString); |
| } |
| Date propertyDateValue = (Date)convertObjectToValue(property, Date.class); |
| return propertyDateValue; |
| } |
| |
| @Override |
| public String getString(Property property) { |
| String propertyStringValue = (String)convertObjectToValue(property, String.class); |
| return propertyStringValue; |
| } |
| |
| @Override |
| public List getList(Property property) { |
| if (null == property) { |
| throw SDOException.cannotPerformOperationOnNullArgument("getList"); |
| } |
| |
| if (((type != null) && !type.isOpen() && property.isOpenContent())) { |
| throw new IllegalArgumentException("Argument not Supported."); |
| } |
| if (!property.isMany()) { |
| throw new ClassCastException("can not call getList for a property that has isMany false."); |
| } |
| |
| /* |
| * Check the currentValueStore map |
| * (1) If the property is stored |
| * (1a) return the ListWrapper or |
| * (1b) return and store an empty default value ListWrapper |
| * (2) if the property is not set |
| * (2a) return and store an empty default value ListWrapper |
| */ |
| Object value = getPropertyInternal(property); |
| if ((value != null) && value instanceof List) { |
| return (List)value; |
| } |
| |
| // get a default empty list |
| List theList = new ListWrapper(this, property); |
| if (getType().isOpen() && property.isOpenContent()) { |
| addOpenContentProperty(property); |
| } |
| |
| // set the property to a default empty list |
| setPropertyInternal((SDOProperty) property, theList, false); |
| return theList; |
| } |
| |
| @Override |
| public void setBoolean(Property property, boolean value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setByte(Property property, byte value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setChar(Property property, char value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setDouble(Property property, double value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setFloat(Property property, float value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setInt(Property property, int value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setLong(Property property, long value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setShort(Property property, short value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setBytes(Property property, byte[] value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setBigDecimal(Property property, BigDecimal value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setBigInteger(Property property, BigInteger value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setDataObject(Property property, DataObject value) { |
| set(property, value); |
| } |
| |
| @Override |
| public void setDate(Property property, Date value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setString(Property property, String value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public void setList(Property property, List value) { |
| convertValueAndSet(property, value); |
| } |
| |
| @Override |
| public DataObject createDataObject(String propertyName) { |
| Property aProperty = getInstanceProperty(propertyName); |
| return createDataObject(aProperty); |
| } |
| |
| @Override |
| public SDODataObject createDataObject(int propertyIndex) { |
| Property aProperty = getInstanceProperty(propertyIndex); |
| return createDataObject(aProperty); |
| } |
| |
| @Override |
| public SDODataObject createDataObject(Property aProperty) { |
| if (aProperty.isContainment()) { |
| Type aType = aProperty.getType(); |
| if (aType != null) { |
| return createDataObject(aProperty, aType); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| public SDODataObject createDataObject(String propertyName, String namespaceURI, String typeName) { |
| Property aProperty = getInstanceProperty(propertyName); |
| Type aType = aHelperContext.getTypeHelper().getType(namespaceURI, typeName); |
| return createDataObject(aProperty, aType); |
| } |
| |
| @Override |
| public SDODataObject createDataObject(int propertyIndex, String namespaceURI, String typeName) { |
| Property aProperty = getInstanceProperty(propertyIndex); |
| Type aType = aHelperContext.getTypeHelper().getType(namespaceURI, typeName); |
| return createDataObject(aProperty, aType); |
| } |
| |
| @Override |
| public SDODataObject createDataObject(Property property, Type aType) { |
| SDODataObject created = (SDODataObject) aHelperContext.getDataFactory().create(aType); |
| |
| if (property.isMany()) { |
| //getList.add will call updateContainment |
| ((ListWrapper)getList(property)).add(created, true); |
| } else { |
| set(property, created); |
| } |
| |
| _setModified(true); |
| created._setCreated(true); |
| |
| return created; |
| } |
| |
| /** |
| * INTERNAL: |
| * Perform a detach on a DataObject or List of DataObjects |
| * @param property |
| * @param oldValue (List or Object) |
| */ |
| private void detach(Property property, Object oldValue) { |
| // This function is called internally from set(property, object, boolean) when a detach of the existing object is required |
| if (property.isMany()) { |
| List oldListValue = (List) oldValue; |
| for (int i = 0, size = oldListValue.size(); i < size; i++) { |
| Object nextValue = oldListValue.get(i); |
| if ((nextValue != null) && (nextValue instanceof SDODataObject)) { |
| ((SDODataObject)nextValue).detachOrDelete(false); |
| } |
| } |
| } else { |
| if ((oldValue != null) && (oldValue instanceof SDODataObject)) { |
| ((SDODataObject)oldValue).detachOrDelete(false); |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Recursively walk the tree and set oldSettings for a detached/deleted object. |
| * This function performs a single preOrder traversal of the tree. |
| * An unset is done for each property if the action = delete |
| * Implementors: detach() and delete() via detach |
| * @param fromDelete (flag the action true = delete, false = detach) |
| */ |
| public void detachOrDelete(boolean fromDelete) { |
| // If we are detaching the root - perform a no-operation |
| if ((null == container) && !fromDelete) { |
| return; |
| } |
| boolean isCSRoot = (null != changeSummary) && (changeSummary.getRootObject() == this); |
| |
| // Detaching the dataObject that is the root of the CS doesn't need to do anything - truncate the recursive traversal |
| if(!fromDelete && isCSRoot){ |
| return; |
| } |
| |
| // This is the root of the recursive loop |
| detachDeleteRecursivePrivate(fromDelete, !isCSRoot, true); |
| } |
| |
| /** |
| * INTERNAL: |
| * Recursively walk the tree and set oldSettings for a detached/deleted object. |
| * @param fromDelete |
| * @param clearCS (true = clear the cs field) = !(is root of the detach/delete subtree the CS root?) |
| * @param isRootOfRecursiveLoop (are we at the root of the detach/delete or inside the subtree) |
| */ |
| private void detachDeleteRecursivePrivate(boolean fromDelete, boolean clearCS, boolean isRootOfRecursiveLoop) { |
| // Store flag for (is root of the detach/delete subtree the CS root?) before we modify it when this object has no container |
| boolean subTreeRootHasCStoClear = clearCS; |
| if (null == getContainer()) { |
| clearCS = false; |
| } |
| if (isRootOfRecursiveLoop || fromDelete) { |
| if (null != getContainer()) { |
| getContainer()._setModified(true); |
| _setContainer(null); |
| _setContainmentPropertyName(null); |
| } |
| } |
| _setDeleted(true); |
| |
| /** Order here is important - the dataGraph pointer should be cleared preorder before we enter the recursive loop to clear child DO's */ |
| DataGraph previousDataGraph = getDataGraph(); |
| // Remove back pointer to containing DataGraph |
| setDataGraph(null); |
| |
| List instancePropertiesList = getInstanceProperties(); |
| for (int i = 0, psize = instancePropertiesList.size(); i < psize; i++) { |
| SDOProperty nextProperty = (SDOProperty)instancePropertiesList.get(i); |
| Object oldValue = get(nextProperty); |
| |
| if (!nextProperty.getType().isChangeSummaryType()) { |
| // Non-containment nodes have changeSummary and dataGraph pointers if they were in a dataGraph |
| if (nextProperty.isContainment() || isContainedByDataGraph(previousDataGraph, nextProperty)) { |
| if (nextProperty.isMany()) { |
| Object manyItem; |
| for (int j = 0, lsize = ((List)oldValue).size(); j < lsize; j++) { |
| manyItem = ((List)oldValue).get(j); |
| detachDeleteRecursivePrivateHelper((SDODataObject)manyItem, fromDelete, clearCS); |
| } |
| } else { |
| detachDeleteRecursivePrivateHelper((SDODataObject)oldValue, fromDelete, clearCS); |
| } |
| } |
| if (fromDelete && !nextProperty.isReadOnly()) { |
| unset(nextProperty, fromDelete); |
| } |
| } |
| } |
| |
| /** |
| * Bug # 6202793 |
| * We delete the changeSummary field in the following use cases |
| * in addition to when the clearCS field was passed in as or transformed to true. |
| * Case 0: detach subtree root from root (with cs) = false |
| * Case 1: detach subtree internal from root (with cs) = false |
| * Case 2: delete subtree root from root (with cs) = false |
| * Case 3: delete subtree internal from root (with cs) = true |
| * Case 4: detach subtree root from root (without cs) = false |
| * Case 5: detach subtree internal from root (without cs) = false |
| * Case 6: delete subtree root from root (without cs) = true |
| * Case 7: delete subtree internal from root (without cs) = true |
| */ |
| if (clearCS || subTreeRootHasCStoClear) { |
| _setChangeSummary(null); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Call detach or delete recursively on aDataObject after possibly changing the flag whether to clear the ChangeSummary pointer at this level |
| * @param aDataObject |
| * @param fromDelete |
| * @param clearCS |
| */ |
| private void detachDeleteRecursivePrivateHelper(SDODataObject aDataObject, boolean fromDelete, boolean clearCS) { |
| if (aDataObject != null) { |
| // Return whether (aDataObject) is the changeSummary root. |
| boolean isCSRoot = (aDataObject.getChangeSummary() != null) &&// |
| (aDataObject.getChangeSummary().getRootObject() == aDataObject); |
| |
| // If we are at the CS root - we do not clear the changeSummary |
| if (isCSRoot) { |
| clearCS = false; |
| } else { |
| if (aDataObject.getContainer() != null) { |
| ChangeSummary containerCS = aDataObject.getContainer().getChangeSummary(); |
| |
| // If there is no CS field set above this object then clear any ChangeSummary pointer at this level |
| if (containerCS == null) { |
| clearCS = true; |
| } |
| } |
| } |
| aDataObject.detachDeleteRecursivePrivate(fromDelete, clearCS, false); |
| } |
| } |
| |
| @Override |
| public void detach() { |
| detachWithSequenceUpdate(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Perform a detach action that originated from a detach and update the sequence. |
| * Case 01 |
| */ |
| private void detachWithSequenceUpdate() { |
| detach(false, true); |
| } |
| |
| /** |
| * INTERNAL: |
| * Perform a detach action that originated from a delete and update the sequence. |
| * Case 11 |
| */ |
| private void deleteWithSequenceUpdate() { |
| detach(true, true); |
| } |
| |
| /** |
| * 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); |
| } |
| } |
| |
| @Override |
| public void delete() { |
| deleteWithSequenceUpdate(); |
| } |
| |
| @Override |
| public SDODataObject getContainer() { |
| return container; |
| } |
| |
| @Override |
| public SDOProperty getContainmentProperty() { |
| if ((container != null) && (containmentPropertyName != null)) { |
| return container.getInstanceProperty(containmentPropertyName); |
| } else { |
| return null; |
| } |
| } |
| |
| @Override |
| public DataGraph getDataGraph() { |
| return dataGraph; |
| } |
| |
| public void setDataGraph(DataGraph dataGraph) { |
| this.dataGraph = dataGraph; |
| } |
| |
| @Override |
| public SDOType getType() { |
| return type; |
| } |
| |
| @Override |
| public List getInstanceProperties() { |
| if (null == instanceProperties) { |
| instanceProperties = new ArrayList(); |
| } |
| return instanceProperties; |
| } |
| |
| @Override |
| public SDOProperty getProperty(String propertyName) { |
| return getInstanceProperty(propertyName); |
| } |
| |
| @Override |
| public SDOProperty getInstanceProperty(String propertyName) { |
| if (getType() == null) { |
| throw new UnsupportedOperationException("Type is null"); |
| } |
| SDOProperty property = getType().getProperty(propertyName); |
| if (null == property) { |
| property = (SDOProperty)_getOpenContentAliasNamesMap().get(propertyName); |
| if (null == property) { |
| for (int i = 0; i < _getOpenContentProperties().size(); i++) { |
| SDOProperty nextProp = (SDOProperty)_getOpenContentProperties().get(i); |
| if (nextProp.getName().equals(propertyName)) { |
| return nextProp; |
| } |
| } |
| if (null == property) { |
| for (int i = 0; i < _getOpenContentPropertiesAttributes().size(); i++) { |
| SDOProperty nextProp = (SDOProperty)_getOpenContentPropertiesAttributes().get(i); |
| if (nextProp.getName().equals(propertyName)) { |
| return nextProp; |
| } |
| } |
| } |
| } |
| } |
| return property; |
| } |
| |
| SDOProperty getInstanceProperty(String propertyName, Object value) { |
| SDOProperty sdoProperty = getInstanceProperty(propertyName); |
| if(null == sdoProperty) { |
| sdoProperty = (SDOProperty) defineOpenContentProperty(propertyName, value); |
| } |
| return sdoProperty; |
| } |
| |
| /** |
| * INTERNAL: |
| * @param propertyIndex |
| * @return |
| * @throws SDOException |
| */ |
| public SDOProperty getInstanceProperty(int propertyIndex) throws IllegalArgumentException { |
| try { |
| SDOProperty property = getInstancePropertiesArray()[propertyIndex]; |
| return property; |
| } catch (IndexOutOfBoundsException e) { |
| throw SDOException.propertyNotFoundAtIndex(e, propertyIndex); |
| } |
| } |
| |
| @Override |
| public SDODataObject getRootObject() { |
| if (getContainer() != null) { |
| return getContainer().getRootObject(); |
| } |
| return this; |
| } |
| |
| @Override |
| public SDOChangeSummary getChangeSummary() { |
| return changeSummary; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set flag created value. |
| * @param created flag created's new value. |
| */ |
| public void _setCreated(boolean created) { |
| if (changeSummary != null) { |
| changeSummary.setCreated(this, created); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Set flag modified value. |
| * @param modified flag modified's new value. |
| */ |
| public void _setModified(boolean modified) { |
| if (changeSummary != null) { |
| if (isLogging()) { |
| updateChangeSummaryWithOriginalValues(); |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Set flag deleted value. |
| * @param deleted flag deleted's new value. |
| */ |
| private void _setDeleted(boolean deleted) { |
| // reduced scope from public to private 17 May 2007 - use the public deprecated public function until we remove it |
| if (changeSummary != null) { |
| boolean wasDeleted = changeSummary.setDeleted(this, deleted); |
| if (wasDeleted && isLogging()) { |
| updateChangeSummaryWithOriginalValues(); |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * @param csm |
| */ |
| private void setChangeSummaryNonRecursive(ChangeSummary csm) { |
| // set changeSummary instance using property |
| changeSummary = (SDOChangeSummary) csm; |
| if (getType() != null) { |
| SDOProperty changeSummaryProperty = getType().getChangeSummaryProperty(); |
| if (changeSummaryProperty != null) { |
| setChangeSummaryProperty(changeSummaryProperty, csm); |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Recursively Set this DataObject's ChangeSummary as passed in value. |
| * @param aChangeSummary the ChangeSummary taking this DataObject as root. |
| */ |
| public void _setChangeSummary(SDOChangeSummary aChangeSummary) { |
| updateChangeSummaryAndDataGraph(aChangeSummary, getDataGraph()); |
| } |
| |
| /** |
| * INTERNAL: |
| * Recursively set this DataObject's changeSummary and dataGraph. |
| * The parent changeSummary and dataGraph may be null. |
| * Preconditions: No changeSummary must exist on the child tree. |
| * Callers: Typically updateContainment (during a set) or delete/detach |
| * of an object without its own changeSummary property. |
| * @param aDataGraph |
| */ |
| private void updateChangeSummaryAndDataGraph(ChangeSummary aChangeSummary, 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(); |
| |
| // Note: Both opposite currentValueStore cannot be isContainment=true |
| // special handling for bidirectional currentValueStore, do a shallow set |
| // 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).updateChangeSummaryAndDataGraph(aChangeSummary, 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).updateChangeSummaryAndDataGraph(aChangeSummary, aDataGraph); |
| } |
| } |
| } |
| } |
| } |
| // Set/Clear changeSummary in postOrder sequence |
| setChangeSummaryNonRecursive(aChangeSummary); |
| } |
| |
| |
| /** |
| * 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(); |
| |
| // Note: Both opposite currentValueStore cannot be isContainment=true |
| // special handling for bidirectional currentValueStore, do a shallow set |
| // 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); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * |
| * @param property |
| * @param value |
| */ |
| private void setChangeSummaryProperty(SDOProperty property, ChangeSummary value) { |
| if (property.isOpenContent()) { |
| throw new IllegalArgumentException("ChangeSummary can not be on an open content property."); |
| } |
| if (property.isMany()) { |
| throw new IllegalArgumentException("ChangeSummary can not be on a property with many set to true."); |
| } |
| |
| if (isLogging()) { |
| _setModified(true); |
| } |
| |
| // process pluggable currentValueStore |
| setPropertyInternal(property, value, true); |
| } |
| |
| /** |
| * 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; |
| } |
| |
| /** |
| * Logic: 4 steps - we defer undo responsibilty to each of DataObject, ListWrapper and Sequence. |
| * 1) swap ValueStores (for DataObject) |
| * 2) swap ListWrapper (if it exists) |
| * 3) swap Sequence (if it exists) |
| * 4) #5928954 restore openContent properties to the 3 data structures on SDODataObject - |
| * openContentPropertiesMap<String,Property>, openContentProperties(List<Property>). instanceProperties (List<Property>) |
| * |
| * Use Cases: |
| * UC1: no change |
| * doDirty=false seqDirty=false |
| * UC2: change non-sequenced do |
| * doDirty=false seqDirty=false |
| * UC3: change sequenced do |
| * doDirty=true. SeqDirty=true |
| * UC4: change unstructured text on sequence only |
| * [doDirty=false seqDirty=true] - special case - verify that we do not do it twice (here and in UC3) |
| * UC5: unset(oc property), undoChanges(), get("open property") |
| * |
| */ |
| |
| // 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()) {// assume sequence is !null |
| // 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()) { |
| // check for modified ListWrapper |
| // 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()); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Process ValueStore changes on any set/delete/detach/unset |
| * when logging is on. |
| */ |
| private void updateChangeSummaryWithOriginalValues() { |
| |
| /** |
| * ValueStore processing: |
| * We switch the current VS to original VS. |
| * The current VS will be a shallow copy of the original for this dataobject at its first change |
| * If the VS is already copied don't reswap them again |
| * |
| * Case: Move/Reset |
| * a detach of a child modifies its parent - trigering a copy of parent's ValueStore |
| * a set on the parent will trigger another copy - but we will skip this one as we already |
| * have a copy of the original. |
| * Issue: if we reset the child back the same place (in effect doing our own undo) |
| * do we optimize this and remove the copy - for now a real undoChanges() will do the same. |
| * |
| */ |
| |
| // dont store an original sequence if there are already is one in the map |
| if (isLogging() && (!getChangeSummary().isDirty(this)) && (!getChangeSummary().isCreated(this))) { |
| // dont copy containers of many props |
| // original valuestore becomes current one (from null) |
| getChangeSummary().getOriginalValueStores().put(this, _getCurrentValueStore()); |
| // we make a shallow copy of the current valuestore arrays at this level in the tree |
| currentValueStore = _getCurrentValueStore().copy(); |
| |
| // handle Sequences only in UC2 where we have modified the container object - not when only the sequence is dirty |
| if (getType().isSequenced()) { |
| // deep copy the list of settings so a modification of the current sequence will not affect a setting in the originalSequences map |
| SDOSequence copySequence = getSequence().copy(); |
| |
| // store original sequence on ChangeSummary |
| getChangeSummary().getOriginalSequences().put(this, copySequence); |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Initialize all old settings related to ChangeSummary and recursively go down |
| * the tree to initialize all DataObjects rooted at this DataObject. |
| */ |
| public void resetChanges() { |
| // fill all oldSettings when logging is turned on |
| if ((container != null) && (containmentPropertyName != null) && (changeSummary != null)) { |
| changeSummary.setOldContainer(this, container); |
| changeSummary.setOldContainmentProperty(this, container.getInstanceProperty(containmentPropertyName)); |
| } |
| |
| // Note: valueStores will not be switched and originalValueStore will continue to be null until the first modification |
| // initialize empty list for current dataObject |
| for(int x=0, instancePropertiesSize=instanceProperties.size(); x<instancePropertiesSize; x++) { |
| SDOProperty property = instanceProperties.get(x); |
| Object value = get(property); |
| |
| // #5878436 12-FEB-07 do not recurse into a non-containment relationship unless inside a dataGraph |
| if ((property.isContainment() || isContainedByDataGraph(property)) && // |
| !property.isMany() && (value != null) && !property.getType().isChangeSummaryType()) { |
| |
| ((SDODataObject)value).resetChanges(); |
| } else { |
| // Handle isMany objects and store the oldCont* values for each item in the list |
| if (property.isMany()) { |
| if (null != value) {// secondary NPE check |
| List listValue = (List) value; |
| for(int y=0, listValueSize=listValue.size(); y<listValueSize; y++) { |
| Object valueMany = listValue.get(y); |
| |
| // do not recurse into a non-containment relationship unless inside a dataGraph |
| if ((property.isContainment() || isContainedByDataGraph(property)) && // |
| (valueMany != null) && !property.getType().isChangeSummaryType()) { |
| ((SDODataObject)valueMany).resetChanges(); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * @param aType |
| */ |
| public void _setType(Type aType) { |
| type = (SDOType) aType; |
| |
| if (getInstanceProperties().isEmpty()) { |
| if (type != null) { |
| getInstanceProperties().addAll(type.getProperties()); |
| } |
| getInstanceProperties().addAll(_getOpenContentProperties()); |
| } |
| |
| if (type != null) { |
| _getCurrentValueStore().initialize(this); |
| // sequence is not initialized unless type.isSequenced=true, null otherwise |
| if (type.isSequenced()) { |
| sequence = new SDOSequence(this); |
| } |
| |
| Property csmProperty = type.getChangeSummaryProperty(); |
| if (csmProperty != null) { |
| SDOChangeSummary aChangeSummary = new SDOChangeSummary(this, aHelperContext); |
| aChangeSummary.endLogging(); |
| _setChangeSummary(aChangeSummary); |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Pluggable Interface for substituting the default Map with a custom Map Class |
| * @param aValueStore |
| */ |
| public void _setCurrentValueStore(ValueStore aValueStore) { |
| currentValueStore = aValueStore; |
| } |
| |
| /** |
| * INTERNAL: |
| * Map interface into the currentValueStore of this DataObject.<br> |
| * Note: Implementers of the {@link ValueStore ValueStore} interface require this accessor. |
| * @return |
| */ |
| public ValueStore _getCurrentValueStore() { |
| // Note: do not remove this function as it is the accessor into the pluggable ValueStore |
| // Notification of any change to this API is required |
| return currentValueStore; |
| } |
| |
| /** |
| * INTERNAL: |
| * Sets the DataObject which contains this DataObject. |
| * @param aContainer the DataObject which is the container of this DataObject. |
| */ |
| public void _setContainer(DataObject aContainer) { |
| container = (SDODataObject) aContainer; |
| } |
| |
| public Map _getOpenContentPropertiesAttributesMap() { |
| Map openContentPropertiesAttrs = new HashMap(); |
| for (int i = 0, size = _getOpenContentPropertiesAttributes().size(); i < size; i++) { |
| Property next = (Property)_getOpenContentPropertiesAttributes().get(i); |
| //if uri is null then attributes won't be prefix qualified |
| QName qname = new QName(((SDOProperty)next).getUri(), next.getName()); |
| openContentPropertiesAttrs.put(qname, get(next)); |
| } |
| |
| return openContentPropertiesAttrs; |
| |
| } |
| |
| public void _setOpenContentPropertiesAttributesMap(Map openAttributeProperties) { |
| Iterator iter = openAttributeProperties.keySet().iterator(); |
| |
| while (iter.hasNext()) { |
| QName nextKey = (QName)iter.next(); |
| |
| if ((!nextKey.getNamespaceURI().equals(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) && (!((nextKey.getNamespaceURI().equals(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI)) && nextKey.getLocalPart().equals(XMLConstants.SCHEMA_TYPE_ATTRIBUTE)))) { |
| Object value = openAttributeProperties.get(nextKey); |
| SDOProperty prop = (SDOProperty)aHelperContext.getXSDHelper().getGlobalProperty(nextKey.getNamespaceURI(), nextKey.getLocalPart(), false); |
| if (prop == null) { |
| DataObject propDo = aHelperContext.getDataFactory().create(SDOConstants.SDO_URL, SDOConstants.PROPERTY); |
| propDo.set("name", nextKey.getLocalPart()); |
| propDo.set("type", SDOConstants.SDO_STRING); |
| propDo.set("many", false); |
| prop = (SDOProperty)aHelperContext.getTypeHelper().defineOpenContentProperty(null, propDo); |
| prop.setInstanceProperty(SDOConstants.XMLELEMENT_PROPERTY, Boolean.FALSE); |
| prop.setUri(nextKey.getNamespaceURI()); |
| |
| set(prop, value); |
| } else { |
| set(prop, value); |
| } |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * This function is implemented by SDOType.setOpen() in a mapping setGet/SetMethodName call |
| * @param openContentPropertiesWithXMLRoots |
| */ |
| public void _setOpenContentPropertiesWithXMLRoots(List openContentPropertiesWithXMLRoots) { |
| for (int i = 0, size = openContentPropertiesWithXMLRoots.size(); i < size; i++) { |
| Object next = openContentPropertiesWithXMLRoots.get(i); |
| String propertyName = null; |
| String propertyUri = null; |
| Object value = null; |
| Type theType = null; |
| if (next instanceof XMLRoot) { |
| XMLRoot nextXMLRoot = (XMLRoot)next; |
| value = nextXMLRoot.getObject(); |
| propertyName = nextXMLRoot.getLocalName(); |
| propertyUri = nextXMLRoot.getNamespaceURI(); |
| if (value instanceof DataObject) { |
| theType = ((DataObject)value).getType(); |
| } else { |
| theType = ((SDOTypeHelper)aHelperContext.getTypeHelper()).getTypeForSimpleJavaType(value.getClass()); |
| } |
| } else if (next instanceof DataObject) { |
| value = next; |
| String qualifiedName = ((SDOType)((DataObject)next).getType()).getXmlDescriptor().getDefaultRootElement(); |
| int colonIndex = qualifiedName.indexOf(':'); |
| if (colonIndex > -1) { |
| String prefix = qualifiedName.substring(0, colonIndex); |
| if ((prefix != null) && !prefix.equals("")) { |
| propertyUri = ((SDOType)((DataObject)next).getType()).getXmlDescriptor().getNonNullNamespaceResolver().resolveNamespacePrefix(prefix); |
| } |
| propertyName = qualifiedName.substring(colonIndex + 1, qualifiedName.length()); |
| } else { |
| propertyName = qualifiedName; |
| } |
| theType = ((DataObject)next).getType(); |
| } |
| else{ |
| theType = ((SDOTypeHelper)aHelperContext.getTypeHelper()).getTypeForSimpleJavaType(next.getClass()); |
| } |
| if (propertyName != null) { |
| SDOProperty prop = (SDOProperty)aHelperContext.getXSDHelper().getGlobalProperty(propertyUri, propertyName, true); |
| if (prop == null) { |
| prop = getInstanceProperty(propertyName); |
| if(prop != null){ |
| if(prop.getUri() == null && propertyUri != null){ |
| prop = createNewProperty(propertyName,propertyUri, theType); |
| }else{ |
| if(prop.getUri() != null){ |
| if(propertyUri == null){ |
| prop = createNewProperty(propertyName,propertyUri, theType); |
| }else if(!prop.getUri().equals(propertyUri)){ |
| prop = createNewProperty(propertyName,propertyUri, theType); |
| } |
| } |
| } |
| }else{ |
| prop = createNewProperty(propertyName,propertyUri, theType); |
| } |
| } |
| |
| if (prop.isMany()) { |
| ((ListWrapper)getList(prop)).add(value, false); |
| } else { |
| set(prop, value, false); |
| } |
| } |
| } |
| } |
| |
| private SDOProperty createNewProperty(String propertyName,String propertyUri, Type theType){ |
| DataObject propDo = aHelperContext.getDataFactory().create(SDOConstants.SDO_URL, SDOConstants.PROPERTY); |
| propDo.set("name", propertyName); |
| propDo.set("type", theType); |
| propDo.set("many", true); |
| SDOProperty prop = (SDOProperty)aHelperContext.getTypeHelper().defineOpenContentProperty(null, propDo); |
| prop.setUri(propertyUri); |
| return prop; |
| } |
| |
| /** |
| * INTERNAL: |
| * This function is implemented by SDOType.setOpen() in a mapping setGet/SetMethodName call |
| * @return |
| */ |
| public List _getOpenContentPropertiesWithXMLRoots() { |
| List returnList = new ArrayList(); |
| for (int i = 0, size = openContentProperties.size(); i < size; i++) { |
| SDOProperty next = (SDOProperty) openContentProperties.get(i); |
| |
| XMLRoot root = new XMLRoot(); |
| String localName = next.getXPath(); |
| if (next.getType() != null) { |
| if (!next.getType().isDataType()) { |
| String uri = next.getUri(); |
| root.setNamespaceURI(uri); |
| } else { |
| String uri = next.getUri(); |
| root.setNamespaceURI(uri); |
| } |
| } |
| |
| root.setLocalName(localName); |
| |
| Object value = get(next); |
| if (next.isMany()) { |
| for (int j = 0, sizel = ((List)value).size(); j < sizel; j++) { |
| XMLRoot nextRoot = new XMLRoot(); |
| nextRoot.setNamespaceURI(root.getNamespaceURI()); |
| nextRoot.setLocalName(root.getLocalName()); |
| Object nextItem = ((List)value).get(j); |
| if ((next.getType() != null) && (next.getType().getXmlDescriptor() == null)) { |
| nextItem = XMLConversionManager.getDefaultXMLManager().convertObject(nextItem, String.class); |
| } |
| nextRoot.setObject(nextItem); |
| returnList.add(nextRoot); |
| } |
| } else { |
| if ((next.getType() != null) && (next.getType().getXmlDescriptor() == null)) { |
| value = XMLConversionManager.getDefaultXMLManager().convertObject(value, String.class); |
| } |
| root.setObject(value); |
| returnList.add(root); |
| } |
| } |
| return returnList; |
| } |
| |
| /** |
| * INTERNAL: |
| * Returns a list of the Properties currently used in this DataObject which are not |
| * included in getType().getProperties |
| * @return the List of open content Properties currently used in this DataObject. |
| */ |
| public List _getOpenContentProperties() { |
| if (openContentProperties == null) { |
| openContentProperties = new ArrayList(); |
| } |
| return openContentProperties; |
| } |
| |
| |
| private Map<String, Property> _getOpenContentAliasNamesMap() { |
| if (openContentAliasNames == null) { |
| openContentAliasNames = new HashMap(); |
| } |
| return openContentAliasNames; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| private void convertValueAndSet(Property property, Object originalValue) { |
| Object convertedValue; |
| if (property.isMany()) { |
| if (originalValue == null) { |
| convertedValue = new ArrayList(); |
| } else if (originalValue instanceof List) { |
| convertedValue = aHelperContext.getDataHelper().convert(property, originalValue); |
| } else { |
| List l = new ArrayList(); |
| l.add(originalValue); |
| convertedValue = aHelperContext.getDataHelper().convert(property, l); |
| } |
| } else { |
| convertedValue = aHelperContext.getDataHelper().convert(property, originalValue); |
| } |
| set(property, convertedValue); |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| private void convertValueAndSet(int propertyIndex, Object originalValue) { |
| Property property = getInstanceProperty(propertyIndex); |
| |
| Object convertedValue = aHelperContext.getDataHelper().convert(property, originalValue); |
| set(property, convertedValue); |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| private void convertValueAndSet(String path, Object originalValue) { |
| XPathEngine.getInstance().set(path, originalValue, this, true); |
| } |
| |
| /** |
| * INTERNAL: |
| * |
| * @param property |
| * @param cls |
| * @return |
| * @throws ClassCastException |
| * @throws IllegalArgumentException |
| */ |
| public Object convertObjectToValue(Property property, Class cls) throws ClassCastException, IllegalArgumentException { |
| //ie get String - convert(thisprop, String.class) |
| if (null == property) { |
| throw new IllegalArgumentException(SDOException.cannotPerformOperationOnNullArgument("convertObjectToValue")); |
| } |
| |
| Object obj = unwrapListValue(property, get(property)); |
| |
| try { |
| return ((SDODataHelper)aHelperContext.getDataHelper()).convertValueToClass(property, obj, cls); |
| } catch (Exception e) { |
| throw new ClassCastException("An error occurred during converison or an unsupported conversion was attempted."); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * |
| * @param property |
| * @param position |
| * @param cls |
| * @return |
| * @throws ClassCastException |
| * @throws IllegalArgumentException |
| */ |
| public Object convertObjectToValue(Property property, int position, Class cls) throws ClassCastException, IllegalArgumentException { |
| if (null == property) { |
| throw new IllegalArgumentException(SDOException.cannotPerformOperationOnNullArgument("convertObjectToValue")); |
| } |
| |
| if ((cls == ClassConstants.List_Class) && !property.isMany()) { |
| throw new ClassCastException("can not call getList for a property that has isMany false."); |
| } |
| |
| Object obj; |
| if (position == -1) { |
| if (cls == ClassConstants.List_Class) { |
| obj = get(property); |
| } else { |
| obj = unwrapListValue(property, get(property)); |
| } |
| } else { |
| obj = getList(property).get(position); |
| } |
| |
| try { |
| return ((SDODataHelper)aHelperContext.getDataHelper()).convertValueToClass(property, obj, cls); |
| } catch (Exception e) { |
| throw new ClassCastException("An error occurred during conversion or an unsupported conversion was attempted."); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Sets the name of the property on the containing DataObject which contains this DataObject as a value. |
| * @param aContainmentPropertyName the name of the property on the containing DataObject which has this DataObject as a value. |
| */ |
| public void _setContainmentPropertyName(String aContainmentPropertyName) { |
| containmentPropertyName = aContainmentPropertyName; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the name of the Property of the DataObject containing this data object |
| * or null if there is no container. |
| * @return the property containing this data object. |
| */ |
| public String _getContainmentPropertyName() { |
| return containmentPropertyName; |
| } |
| |
| /** |
| * INTERNAL: |
| * |
| * @param value |
| * @return |
| */ |
| public boolean parentContains(Object value) { |
| if ((value == null) || (!(value instanceof DataObject))) { |
| return false; |
| } |
| if ((getContainer() != null) && (getContainmentProperty() != null)) { |
| if (value.equals(getContainer())) { |
| return true; |
| } |
| return getContainer().parentContains(value); |
| } |
| return false; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return whether the current dataObject(this) is part of a dataGraph. |
| * Typically this is used to determine whether to treat !isContainment dataObjects as containment while inside a dataGraph. |
| * @param aProperty |
| * @return |
| */ |
| private boolean isContainedByDataGraph(Property aProperty) { |
| // The property is of type DataObject that points to a DataGraph |
| return isContainedByDataGraph(getDataGraph(), (SDOProperty) aProperty); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return whether the current dataObject(this) is was part of the passed in dataGraph. |
| * Typically this is used to determine whether to treat !isContainment dataObjects as containment while inside a dataGraph. |
| * The dataGraph input is used when the current DataGraph pointer has already been cleared |
| * @param aDataGraph |
| * @param aProperty |
| * @return |
| */ |
| private boolean isContainedByDataGraph(DataGraph aDataGraph, SDOProperty aProperty) { |
| // The property is of type DataObject that points to a DataGraph |
| return (null != aDataGraph) && (null != aProperty.getType()) && !aProperty.getType().isDataType(); |
| } |
| |
| /** |
| * INTERNAL: |
| * Update containment with flagged update sequence state |
| * @param property |
| * @param values |
| * @param updateSequence |
| */ |
| public void updateContainment(Property property, Collection values, boolean updateSequence) { |
| if (property.isContainment() || isContainedByDataGraph(property)) {// |
| |
| Object[] valuesArray = values.toArray(); |
| for(int i=0; i<valuesArray.length; i++){ |
| Object next = valuesArray[i]; |
| if (next instanceof SDODataObject) { |
| updateContainment(property, (SDODataObject)next, updateSequence); |
| } |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Update containment on the specified collection of values and default to true = update the sequence |
| * @param property |
| * @param values |
| */ |
| public void updateContainment(Property property, Collection values) { |
| updateContainment(property, values, true); |
| } |
| |
| /** |
| * 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); |
| } |
| |
| // Check that the target object is not a changeSummary root - an internal set of an internal changeSummary |
| /** |
| * 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); |
| } |
| |
| // If we are adding a previously deleted object, we must cancel out the isDeleted with an isCreated |
| // 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); |
| |
| // In the case of re-adding a previously deleted/detached data object, we may need to update |
| // 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); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * update containment and the update the sequence value by default. |
| * @param property |
| * @param value |
| */ |
| public void updateContainment(Property property, SDODataObject value) { |
| updateContainment(property, value, true); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the changeSummary logging state |
| * @return |
| */ |
| private boolean isLogging() { |
| return ((changeSummary != null) && changeSummary.isLogging()); |
| } |
| |
| /** |
| * INTERNAL: |
| * Defined in SDO 2.01 spec on page 65 Externalizable function is called by |
| * ObjectStream.writeObject() A replacement object for serialization can be |
| * called here. |
| * <p>Security Note: |
| * This public function exposes a data replacement vulnerability where an outside client |
| * can gain access and modify their non-final constants. |
| * We may need to wrap the GZIP streams in some sort of encryption when we are not |
| * using HTTPS or SSL/TLS on the wire. |
| * |
| * @see org.eclipse.persistence.sdo.SDOResolvable |
| */ |
| public Object writeReplace() { |
| // JIRA129: pass the helperContext to the constructor to enable non-static contexts |
| return new SDOExternalizableDelegator(this, aHelperContext); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the SDO Path from the root to the current internal node |
| * |
| * Prereq: We know that the targetObject will always have a parent as called |
| * from getPath() |
| * |
| * Matching conditions: |
| * Iterate up the tree |
| * return a non-null string for the XPath at when we reach the root node |
| * |
| * Function is partially based on SDOCopyHelper.copy(DataObject dataObject) |
| * |
| * Performance: This function is O(log n) where n=# of children in the tree |
| * |
| * @param currentPath |
| * @param targetObject |
| * @param aSeparator (XPath separator is written only between elements not for the first call) |
| * @return String (representing the XPath) |
| */ |
| private String getPathPrivate(String currentPath,// |
| SDODataObject targetObject,// |
| String aSeparator) { |
| // Base Case: check we are at the root (get parent first) |
| SDODataObject aParent = targetObject.getContainer(); |
| if (aParent == null) { |
| // check for indexed property if root is a ListWrapper |
| return currentPath; |
| } |
| |
| // Recursive Case: O(log(n)) recursive calls, 1 for each tree level |
| // get parent property based on parent property name in target, property will always be set |
| String aContainmentPropertyName = targetObject._getContainmentPropertyName(); |
| SDOProperty aChild = aParent.getInstanceProperty(aContainmentPropertyName); |
| |
| // Handle ListWrapper contained DataObjects |
| if (aChild.isMany()) { |
| int index = (aParent.getList(aChild)).indexOf(targetObject); |
| |
| return getPathPrivate(aContainmentPropertyName +// |
| SDOConstants.SDO_XPATH_LIST_INDEX_OPEN_BRACKET +// |
| (1 + index) +// [indexes] start at 1 |
| SDOConstants.SDO_XPATH_LIST_INDEX_CLOSE_BRACKET +// |
| aSeparator +// |
| currentPath,// |
| aParent,// |
| SDOConstants.SDO_XPATH_SEPARATOR_FRAGMENT); |
| } |
| |
| // recursive call to non ListWrappers |
| return getPathPrivate(aContainmentPropertyName +// |
| aSeparator +// |
| currentPath,// |
| aParent,// |
| SDOConstants.SDO_XPATH_SEPARATOR_FRAGMENT); |
| } |
| |
| /** |
| * INTERNAL: |
| * Return an SDO Path string from root of the caller to itself |
| * @return String |
| */ |
| public String _getPath() { |
| // Base Case: The internal node is actually the root |
| if (getContainer() == null) { |
| return SDOConstants.SDO_XPATH_TO_ROOT; |
| } else { |
| // Recursive Case: call private recursive reverse O(logn) traversal |
| // function on root object |
| return getPathPrivate(SDOConstants.EMPTY_STRING,// |
| this,// |
| SDOConstants.EMPTY_STRING); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * |
| * @return |
| */ |
| private SDOProperty[] getInstancePropertiesArray() { |
| if ((openContentProperties == null) || openContentProperties.isEmpty()) { |
| return getType().getPropertiesArray(); |
| } |
| |
| SDOProperty[] props = getType().getPropertiesArray(); |
| SDOProperty[] ret = new SDOProperty[openContentProperties.size() + props.length]; |
| for (int i = 0; i < props.length; i++) { |
| ret[i] = props[i]; |
| } |
| for (int i = props.length; i < ret.length; i++) { |
| ret[i] = (SDOProperty)openContentProperties.get(i - props.length); |
| } |
| return ret; |
| } |
| |
| /** |
| * INTERNAL: |
| * Get the value of the property (open-content or declared).. |
| * @param property |
| * @return |
| */ |
| public Object getPropertyInternal(Property property) { |
| int index = ((SDOProperty)property).getIndexInType(); |
| if (index == -1) { |
| return _getCurrentValueStore().getOpenContentProperty(property); |
| } else { |
| return _getCurrentValueStore().getDeclaredProperty(index); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Update the ValueStore with the new property value and update any sequence if it exists. |
| * @param property |
| * @param value |
| * @param updateSequence (truncate call back from sequence when this function was called from sequence) |
| */ |
| public void setPropertyInternal(SDOProperty property, Object value, boolean updateSequence) { |
| /* |
| * Update sequence object if element and without invoking a back pointer from sequence.add() to this dataObject. |
| * The sequence != null required in case where non-public type.setSequenced(true) called after type define. |
| * Assume: aHelperContext is assumed not to be null. |
| * ChangeSummaries are not part of sequences. |
| * |
| * See JIRA-242, bug#6031657: A modify operation will need logic to either |
| * 1 - update the existing setting in place |
| * 2 - add a new setting and remove the previous one - TBD |
| * |
| * The following code needs to check for !attribute instead of !element because |
| * we have 3 states( !attribute, !element and (!attribute && !element)) |
| * - two of which are valid for sequence setting creation. |
| */ |
| Object origValue = getPropertyInternal(property); |
| |
| if (type.isSequenced() && updateSequence// |
| &&!property.getType().isChangeSummaryType() && !aHelperContext.getXSDHelper().isAttribute(property)) { |
| // As we do for ListWrappers and DataObjects we will need to remove the previous setting if this set is actually a modify |
| // keep sequence code here for backdoor sets |
| if(property.isMany()) { |
| getSequence().addSettingWithoutModifyingDataObject(property, value); |
| } else { |
| if(isSet(property)) { |
| getSequence().updateSettingWithoutModifyingDataObject(property, get(property), value); |
| } else { |
| getSequence().addSettingWithoutModifyingDataObject(property, value); |
| } |
| } |
| } |
| |
| int index = property.getIndexInType(); |
| if (index == -1) { |
| _getCurrentValueStore().setOpenContentProperty(property, value); |
| } else { |
| _getCurrentValueStore().setDeclaredProperty(index, value); |
| SDOProperty oppositeProperty = property.getOpposite(); |
| if(null != oppositeProperty) { |
| if(null != value) { |
| if(property.isMany()) { |
| List<SDODataObject> valueList = (List<SDODataObject>) value; |
| for(SDODataObject valueDO : valueList) { |
| if(this != valueDO.get(oppositeProperty)) { |
| valueDO.setInternal(oppositeProperty, this, true); |
| } |
| } |
| } else { |
| SDODataObject valueDO = (SDODataObject) value; |
| if(oppositeProperty.isMany()) { |
| List oppositeList = valueDO.getList(oppositeProperty); |
| if(!oppositeList.contains(this)) { |
| oppositeList.add(this); |
| } |
| } else { |
| if(this != valueDO.get(oppositeProperty)) { |
| valueDO.setInternal(oppositeProperty, this, true); |
| } |
| } |
| } |
| } |
| |
| if(null != origValue) { |
| if(property.isMany()) { |
| List<SDODataObject> origValueList = (List<SDODataObject>) origValue; |
| for(SDODataObject origValueDO : origValueList) { |
| if(null != origValueDO.get(oppositeProperty)) { |
| origValueDO.set(oppositeProperty, null); |
| } |
| } |
| } else { |
| DataObject origValueDO = (DataObject) origValue; |
| if(oppositeProperty.isMany()) { |
| List oppositeList = origValueDO.getList(oppositeProperty); |
| if(oppositeList.contains(this)) { |
| oppositeList.remove(this); |
| } |
| } else { |
| if(null != origValueDO.get(oppositeProperty)) { |
| origValueDO.set(oppositeProperty, null); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Add the open content property into all 3 data structures. |
| * Remove the property from the unset map. |
| * @param property |
| */ |
| public void addOpenContentProperty(Property property) { |
| List theList = null; |
| if (aHelperContext.getXSDHelper().isAttribute(property)) { |
| theList = _getOpenContentPropertiesAttributes(); |
| }else { |
| theList = _getOpenContentProperties(); |
| } |
| |
| if (!theList.contains(property)) { |
| if (isLogging()) { |
| getChangeSummary().removeUnsetOCProperty(this, property); |
| } |
| theList.add(property); |
| getInstanceProperties().add(property); |
| if (((SDOProperty)property).hasAliasNames()) { |
| for (int i = 0, size = property.getAliasNames().size(); i < size; i++) { |
| _getOpenContentAliasNamesMap().put((String) property.getAliasNames().get(i), property); |
| } |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Remove the open content property (property) from all 3 data structures. |
| * Add the property to the unset map. |
| * We restore this OC property in undoChanges |
| * @param property |
| */ |
| public void removeOpenContentProperty(Property property) { |
| // save OC property in changeSummary for use during cs.copy and undoChanges |
| if (isLogging()) { |
| getChangeSummary().setUnsetOCProperty(this, property); |
| } |
| |
| // remove oc property |
| _getOpenContentProperties().remove(property); |
| _getOpenContentPropertiesAttributes().remove(property); |
| getInstanceProperties().remove(property); |
| if (((SDOProperty)property).hasAliasNames()) { |
| for (int i = 0, size = property.getAliasNames().size(); i < size; i++) { |
| _getOpenContentAliasNamesMap().remove(property.getAliasNames().get(i)); |
| } |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Return whether the property (open-content or declared) is set? |
| * @param property |
| * @return true if set, false otherwise |
| */ |
| public boolean isSetInternal(Property property) { |
| int index = ((SDOProperty)property).getIndexInType(); |
| if (index == -1) { |
| return _getCurrentValueStore().isSetOpenContentProperty(property); |
| } else { |
| return _getCurrentValueStore().isSetDeclaredProperty(index); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Unset the property on the ValueStore interface and update the sequence if it exists. |
| * Used by implementers that require |
| * @param property |
| * @param updateSequence |
| */ |
| private void unsetInternal(Property property, boolean updateSequence) { |
| if (property.isMany()) { |
| getList(property).clear(); |
| if (property.isOpenContent()) { |
| removeOpenContentProperty(property); |
| } else { |
| _getCurrentValueStore().unsetDeclaredProperty(((SDOProperty)property).getIndexInType()); |
| } |
| } else { |
| if (property.isOpenContent()) { |
| _getCurrentValueStore().unsetOpenContentProperty(property); |
| removeOpenContentProperty(property); |
| } else { |
| _getCurrentValueStore().unsetDeclaredProperty(((SDOProperty)property).getIndexInType()); |
| } |
| } |
| |
| /* |
| * Update sequence object if element and without invoking a back pointer from sequence.add() to this dataObject. |
| * The sequence != null required in case where non-public type.setSequenced(true) called after type define |
| */ |
| if (type.isSequenced() && (sequence != null) && updateSequence && aHelperContext.getXSDHelper().isElement(property)) { |
| // remove all instances of the property from the sequence |
| sequence.removeSettingWithoutModifyingDataObject(property); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the sdoref attribute value during unmarshaling |
| * @return |
| */ |
| public String _getSdoRef() { |
| return sdoRef; |
| } |
| |
| public void _setOpenContentPropertiesAttributes(List openContentPropertiesAttributes) { |
| this.openContentPropertiesAttributes = openContentPropertiesAttributes; |
| } |
| |
| public List _getOpenContentPropertiesAttributes() { |
| if (openContentPropertiesAttributes == null) { |
| openContentPropertiesAttributes = new ArrayList(); |
| } |
| return openContentPropertiesAttributes; |
| } |
| |
| @Override |
| public List<Setting> getSettings() { |
| if(null != sequence) { |
| return getSequence().getSettings(); |
| } else { |
| return null; |
| } |
| } |
| |
| public void _setSdoRef(String newRef) { |
| sdoRef = newRef; |
| } |
| |
| /** |
| * Convenience method that unwraps a list and returns the first element, |
| * if necessary. |
| * |
| * @param prop |
| * @param val |
| * @return |
| */ |
| private Object unwrapListValue(Property prop, Object val) { |
| if (prop == null || val == null) { |
| return null; |
| } |
| if (! (prop.isMany() && val instanceof ListWrapper) ) { |
| return val; |
| } |
| List l = (ListWrapper) val; |
| if (l.size() == 0) { |
| return null; |
| } |
| return l.get(0); |
| } |
| |
| } |