| /* |
| * 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; |
| } |
| } |