blob: 429ad80897310ec8af08a4d7ffe22bd8f9b0f6a7 [file] [log] [blame]
/*
* Copyright (c) 1998, 2020 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 commonj.sdo.DataObject;
import commonj.sdo.Property;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* <p><b>Purpose</b>:Default implementation of the ValueStore interface.
* <p><b>Responsibilities</b>:<ul>
* <li> Provide get/set/isset/unset access to the values of a DataObject
* <li> Store the values of the declared and open content propeties in memory
* </ul>
*/
public class DefaultValueStore implements ValueStore {
private Map openContentValues;//open content values keyed on real prop name
private Object[] typePropertyValues;
/** Visibility reduced from [public] in 2.1.0. May 15 2007 */
private boolean[] typePropertiesIsSetStatus;
private DataObject dataObject;
public DefaultValueStore() {
}
@Override
public Object getDeclaredProperty(int propertyIndex) {
if (typePropertyValues != null) {
return typePropertyValues[propertyIndex];
}
return null;
}
@Override
public Object getOpenContentProperty(Property property) {
return getOpenContentValues().get(property);
}
@Override
public void setDeclaredProperty(int propertyIndex, Object value) {
getTypePropertyValues()[propertyIndex] = value;
getTypePropertiesIsSetStatus()[propertyIndex] = true;
}
@Override
public void setOpenContentProperty(Property property, Object value) {
getOpenContentValues().put(property, value);
}
@Override
public boolean isSetDeclaredProperty(int propertyIndex) {
boolean[] typePropertiesIsSetStatus = getTypePropertiesIsSetStatus();
if(propertyIndex >= typePropertiesIsSetStatus.length) {
// New properties have been added to the type since the DataObject
// was created so return false to indicate that the new property has
// not been set.
return false;
}
return typePropertiesIsSetStatus[propertyIndex];
}
@Override
public boolean isSetOpenContentProperty(Property property) {
return getOpenContentValues().containsKey(property);
}
@Override
public void unsetDeclaredProperty(int propertyIndex) {
Property prop = ((SDODataObject)dataObject).getInstanceProperty(propertyIndex);
if (!prop.isMany()) {
getTypePropertyValues()[propertyIndex] = null;
}
getTypePropertiesIsSetStatus()[propertyIndex] = false;
}
@Override
public void unsetOpenContentProperty(Property property) {
getOpenContentValues().remove(property);
}
/**
* Perform any post-instantiation integrity operations that could not be done during
* ValueStore creation.<br>
* Since the dataObject reference passed in may be bidirectional or self-referencing
* - we cannot set this variable until the dataObject itself is finished instantiation
* - hence the 2-step initialization.
*
* @param aDataObject
*/
@Override
public void initialize(DataObject aDataObject) {
dataObject = aDataObject;
setTypePropertiesIsSetStatus(new boolean[aDataObject.getType().getProperties().size()]);
setTypePropertyValues(new Object[aDataObject.getType().getProperties().size()]);
}
/**
* Set the values for declared properties
* @param typePropertyValuesArray
*/
public void setTypePropertyValues(Object[] typePropertyValuesArray) {
typePropertyValues = typePropertyValuesArray;
}
/**
* INTERNAL:
* @param typePropertiesIsSetStatusArray boolean[] of isSet values for declared properties
*/
public void setTypePropertiesIsSetStatus(boolean[] typePropertiesIsSetStatusArray) {
typePropertiesIsSetStatus = typePropertiesIsSetStatusArray;
}
/**
* INTERNAL:
* @return Object[] of the values of declared properties
*/
public Object[] getTypePropertyValues() {
return typePropertyValues;
}
/**
* INTERNAL:
* @return boolean[] of isSet values for declared properties
*/
public boolean[] getTypePropertiesIsSetStatus() {
return typePropertiesIsSetStatus;
}
/**
* INTERNAL:
* @param openContentValues
*/
public void setOpenContentValues(Map openContentValues) {
this.openContentValues = openContentValues;
}
/**
* INTERNAL:
* @return Non-null Map of values for open content properties
*/
public Map getOpenContentValues() {
if (openContentValues == null) {
openContentValues = new HashMap();
}
return openContentValues;
}
// Do not implement this function unless the valueStore handles its own object wrapping
@Override
public void setManyProperty(Property property, Object value) {
}
/**
* Get a shallow copy of the original ValueStore.
* Changes made to the copy must not impact the original ValueStore
* @return ValueStore
*/
@Override
public ValueStore copy() {
/**
* Implementer: SDODataObject.resetChanges()
*/
DefaultValueStore anOriginalValueStore = new DefaultValueStore();
anOriginalValueStore.dataObject = dataObject;
boolean[] currentIsSet = getTypePropertiesIsSetStatus();
boolean[] isSetCopy = new boolean[currentIsSet.length];
System.arraycopy(currentIsSet, 0, isSetCopy, 0, currentIsSet.length);
Object[] currentValues = getTypePropertyValues();
Object[] valueCopy = new Object[currentValues.length];
System.arraycopy(currentValues, 0, valueCopy, 0, currentValues.length);
// shallow copy isSet boolean
anOriginalValueStore.setTypePropertiesIsSetStatus(isSetCopy);
// shallow copy the object values
anOriginalValueStore.setTypePropertyValues(valueCopy);
HashMap clonedMap = new HashMap();
/**
* Note: if the oc Map is null we will return an empty map
* this empty Map will be set on the copy but the original will still actually have a null Map
* this is ok because any get on the original will create a new Map and we will
* not have object equality between copy and original oc maps
* Just be aware that the two openContentValues will not pass value equility unless
* the public get function is used
*/
clonedMap.putAll(getOpenContentValues());
// shallow copy oc values
anOriginalValueStore.setOpenContentValues(clonedMap);
return anOriginalValueStore;
}
/**
* Indicates if a given ValueStore is equal to this. The following
* attributes are tested for equality:
* - data object
* - type property values
* - open content property values
* - property isSet values
*/
@Override
public boolean equals(Object obj) {
DefaultValueStore dvs;
try {
dvs = (DefaultValueStore) obj;
} catch (ClassCastException cce) {
return false;
}
// Compare data object
if (dvs.dataObject != this.dataObject) {
return false;
}
// Compare declared properties and isSet status
// All lists must be the same length
if (dvs.getTypePropertyValues().length != this.getTypePropertyValues().length ||
dvs.getTypePropertiesIsSetStatus().length != this.getTypePropertiesIsSetStatus().length) {
return false;
}
for (int i=0; i<dvs.getTypePropertyValues().length; i++) {
// isSet values must be equal
if (dvs.isSetDeclaredProperty(i) != this.isSetDeclaredProperty(i)) {
return false;
}
Object dvsPropVal = dvs.getDeclaredProperty(i);
Object thisPropVal = this.getDeclaredProperty(i);
// Both values need to be null or non-null
if (dvsPropVal == null) {
if (thisPropVal != null) {
return false;
}
// Here both are null so no need to check anything
} else {
if (!(dvsPropVal.equals(thisPropVal))) {
return false;
}
}
}
// Compare open content properties
if (dvs.getOpenContentValues().size() != this.getOpenContentValues().size()) {
return false;
}
Iterator<Property> keyIt = dvs.getOpenContentValues().keySet().iterator();
while (keyIt.hasNext()) {
Property key = keyIt.next();
Object dvsOCVal = dvs.getOpenContentProperty(key);
Object thisOCVal = this.getOpenContentProperty(key);
// Both values need to be null or non-null
if (dvsOCVal == null) {
if (thisOCVal != null) {
return false;
}
// Here both are null so no need to check anything
} else {
if (!(dvsOCVal.equals(thisOCVal))) {
return false;
}
}
}
return true;
}
@Override
public int hashCode() {
Object[] typePropertyValues = getTypePropertyValues();
boolean[] typePropertiesIsSetStatus = getTypePropertiesIsSetStatus();
int result = dataObject != null ? dataObject.hashCode() : 0;
result = 31 * result + (typePropertyValues != null ? Arrays.hashCode(typePropertyValues) : 0);
result = 31 * result + (typePropertiesIsSetStatus != null ? Arrays.hashCode(typePropertiesIsSetStatus) : 0);
result = 31 * result + getOpenContentValues().hashCode();
return result;
}
}