/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.sdo; 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() { } public Object getDeclaredProperty(int propertyIndex) { if (typePropertyValues != null) { return typePropertyValues[propertyIndex]; } return null; } public Object getOpenContentProperty(Property property) { return getOpenContentValues().get(property); } public void setDeclaredProperty(int propertyIndex, Object value) { getTypePropertyValues()[propertyIndex] = value; getTypePropertiesIsSetStatus()[propertyIndex] = true; } public void setOpenContentProperty(Property property, Object value) { getOpenContentValues().put(property, value); } 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]; } public boolean isSetOpenContentProperty(Property property) { return getOpenContentValues().containsKey(property); } public void unsetDeclaredProperty(int propertyIndex) { Property prop = ((SDODataObject)dataObject).getInstanceProperty(propertyIndex); if (!prop.isMany()) { getTypePropertyValues()[propertyIndex] = null; } getTypePropertiesIsSetStatus()[propertyIndex] = false; } 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 */ 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 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 */ 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 */ 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; } }