gt:         throw new UnsupportedOperationException();
context: /*******************************************************************************
  * 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:
  *     bdoughan - Jan 27/2009 - 1.1 - Initial implementation
  *     bdoughan - Mar 31/2009 - 2.0 - Added ChangeSummary Support
  ******************************************************************************/
  package org.eclipse.persistence.sdo.helper.jaxb;
  
  import java.util.Collection;
  import java.util.List;
  import java.util.Map;
  import java.util.WeakHashMap;
  
  import org.eclipse.persistence.core.mappings.CoreAttributeAccessor;
  import org.eclipse.persistence.exceptions.SDOException;
  import org.eclipse.persistence.internal.core.helper.CoreField;
  import org.eclipse.persistence.internal.core.queries.CoreContainerPolicy;
  import org.eclipse.persistence.internal.oxm.MappingNodeValue;
  import org.eclipse.persistence.internal.oxm.TreeObjectBuilder;
  import org.eclipse.persistence.internal.oxm.XPathFragment;
  import org.eclipse.persistence.internal.oxm.XPathNode;
  import org.eclipse.persistence.internal.oxm.mappings.Mapping;
  import org.eclipse.persistence.internal.queries.ContainerPolicy;
  import org.eclipse.persistence.internal.sessions.AbstractSession;
  import org.eclipse.persistence.jaxb.JAXBContext;
  import org.eclipse.persistence.mappings.ContainerMapping;
  import org.eclipse.persistence.mappings.DatabaseMapping;
  import org.eclipse.persistence.oxm.XMLDescriptor;
  import org.eclipse.persistence.oxm.XMLField;
  import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping;
  import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
  import org.eclipse.persistence.oxm.mappings.XMLDirectMapping;
  import org.eclipse.persistence.oxm.mappings.XMLObjectReferenceMapping;
  import org.eclipse.persistence.sdo.SDOChangeSummary;
  import org.eclipse.persistence.sdo.SDODataObject;
  import org.eclipse.persistence.sdo.SDOProperty;
  import org.eclipse.persistence.sdo.SDOType;
  import org.eclipse.persistence.sdo.ValueStore;
  import org.eclipse.persistence.sdo.helper.ListWrapper;
  
  import commonj.sdo.DataObject;
  import commonj.sdo.Property;
  
  /**
   * The JAXBValueStore enables a DataObject to access data from a POJO.
   * The link between an SDO property and a POJO property is through their
   * XML representation.  For the POJO property this corresponds to its
   * JAXB mapping.
   */
  public class JAXBValueStore implements ValueStore {
  
      private JAXBHelperContext jaxbHelperContext;
      private Object entity;
      private XMLDescriptor descriptor;
      private SDODataObject dataObject;
      private Map<Property, JAXBListWrapper> listWrappers;
  
      public JAXBValueStore(JAXBHelperContext aJAXBHelperContext, SDOType sdoType) {
          this.jaxbHelperContext = aJAXBHelperContext;
          this.listWrappers = new WeakHashMap<Property, JAXBListWrapper>();
          this.descriptor = jaxbHelperContext.getObjectDescriptor(sdoType);
          this.entity = this.descriptor.getInstantiationPolicy().buildNewInstance();
      }
  
      public JAXBValueStore(JAXBHelperContext aJAXBHelperContext, Object anEntity) {
          this.jaxbHelperContext = aJAXBHelperContext;
          this.listWrappers = new WeakHashMap<Property, JAXBListWrapper>();
          JAXBContext jaxbContext = (JAXBContext) jaxbHelperContext.getJAXBContext();
          this.descriptor = (XMLDescriptor) jaxbContext.getXMLContext().getSession(anEntity).getDescriptor(anEntity);
          this.entity = anEntity;
      }
  
      private JAXBValueStore(JAXBHelperContext aJAXBHelperContext, Object anEntity, XMLDescriptor aDescriptor, SDODataObject aDataObject, Map<Property, JAXBListWrapper> aMap) {
          this.jaxbHelperContext = aJAXBHelperContext;
          this.entity = anEntity;
          this.descriptor = aDescriptor;
          this.dataObject = aDataObject;
          this.listWrappers = aMap;
  
          for(JAXBListWrapper jaxbListWrapper : listWrappers.values()) {
              jaxbListWrapper.getCurrentElements().setValueStore(this);
          }
      }
  
      /**
       * Return the DataObject associated with this value store.
       */
      SDODataObject getDataObject() {
          return dataObject;
      }
  
      /**
       * Return the POJO associated with this value store.
       */
      Object getEntity() {
          return entity;
      }
  
      /**
       * Return the XMLDescriptor associated with this value store.
       * This is the XMLDescriptor for the associated POJO.
       */
      XMLDescriptor getEntityDescriptor() {
          return descriptor;
      }
  
      /**
       * Return the JAXBHelperContext.  This is the JAXBHelperContext
       * used to create the DataObject.
       */
      JAXBHelperContext getJAXBHelperContext() {
          return jaxbHelperContext;
      }
  
      /**
       * Initialize the value store with its associated DataObject.
       */
      public void initialize(DataObject aDataObject) {
          this.dataObject = (SDODataObject) aDataObject;
      }
  
      /**
       * Get the value from the wrapped POJO, wrapping in DataObjects as
       * necessary.
       */
      public Object getDeclaredProperty(int propertyIndex) {
          SDOProperty declaredProperty = (SDOProperty) dataObject.getType().getDeclaredProperties().get(propertyIndex);
          if(declaredProperty.getType().isChangeSummaryType()) {
              return dataObject.getChangeSummary();
          }
          Mapping mapping = this.getJAXBMappingForProperty(declaredProperty);
          Object value = mapping.getAttributeAccessor().getAttributeValueFromObject(entity);
          if (declaredProperty.isMany()) {
              JAXBListWrapper listWrapper = listWrappers.get(declaredProperty);
              if (null != listWrapper) {
                  return listWrapper;
              }
              listWrapper = new JAXBListWrapper(this, declaredProperty);
              listWrappers.put(declaredProperty, listWrapper);
              return listWrapper;
          } else if(null == value || declaredProperty.getType().isDataType()) {
              return value;
          } else {
              if(declaredProperty.isContainment()) {
                  return jaxbHelperContext.wrap(value, declaredProperty, dataObject);
              } else {
                  return jaxbHelperContext.wrap(value);
              }
          }
      }
  
      /**
       * Set the value on the underlying POJO, unwrapping values as necessary.
       */
      public void setDeclaredProperty(int propertyIndex, Object value) {
          SDOProperty declaredProperty = (SDOProperty) dataObject.getType().getDeclaredProperties().get(propertyIndex);
          if(declaredProperty.getType().isChangeSummaryType()) {
              return;
          }
  
          Mapping mapping = this.getJAXBMappingForProperty(declaredProperty);
  
          Object newValue = value;
          Object oldValue = mapping.getAttributeAccessor().getAttributeValueFromObject(entity);
  
          if (declaredProperty.getType().isDataType()) {
              if (!declaredProperty.isMany()) {
                  AbstractSession session = ((JAXBContext) jaxbHelperContext.getJAXBContext()).getXMLContext().getSession(entity);
                  XMLDirectMapping directMapping = (XMLDirectMapping) mapping;
                  if (directMapping.hasConverter()) {
                      newValue = directMapping.getConverter().convertDataValueToObjectValue(newValue, session);
                  } else {
                      CoreField field = mapping.getField();
                      newValue = session.getDatasourcePlatform().getConversionManager().convertObject(newValue, descriptor.getObjectBuilder().getFieldClassification((XMLField) field));
                  }
              }
              mapping.setAttributeValueInObject(entity, newValue);
          } else if (declaredProperty.isMany()) {
              // Get a ListWrapper and set it's current elements
              ListWrapper listWrapper = (ListWrapper) getDeclaredProperty(propertyIndex);
              listWrapper.addAll((List) newValue);
          } else {
              // OLD VALUE
              if (mapping.isAbstractCompositeObjectMapping()) {
                  XMLCompositeObjectMapping compositeMapping = (XMLCompositeObjectMapping) mapping;
                  if (oldValue != null && compositeMapping.getContainerAccessor() != null) {
                      compositeMapping.getContainerAccessor().setAttributeValueInObject(oldValue, null);
                  }
              }
  
              // NEW VALUE
              newValue = jaxbHelperContext.unwrap((DataObject) value);
              mapping.getAttributeAccessor().setAttributeValueInObject(entity, newValue);
              if (mapping.isAbstractCompositeObjectMapping()) {
                  XMLCompositeObjectMapping compositeMapping = (XMLCompositeObjectMapping) mapping;
                  if (value != null && compositeMapping.getContainerAccessor() != null) {
                      compositeMapping.getContainerAccessor().setAttributeValueInObject(newValue, entity);
                  }
              }
          }
  
      }
  
      /**
       * For isMany=false properties return true if not null. For collection properties
       * return true if the collection is not empty.
       */
      public boolean isSetDeclaredProperty(int propertyIndex) {
          SDOProperty declaredProperty = (SDOProperty) dataObject.getType().getDeclaredProperties().get(propertyIndex);
          if(declaredProperty.getType().isChangeSummaryType()) {
              return true;
          }
          Mapping mapping = this.getJAXBMappingForProperty(declaredProperty);
          if (declaredProperty.isMany()) {
              Collection collection = (Collection) mapping.getAttributeAccessor().getAttributeValueFromObject(entity);
              if (null == collection) {
                  return false;
              }
              return !collection.isEmpty();
          } else {
              return null != mapping.getAttributeAccessor().getAttributeValueFromObject(entity);
          }
      }
  
      /**
       * For isMany=false properties set the value to null. For isMany=true set
       * the value to an empty container of the appropriate type.
       */
      public void unsetDeclaredProperty(int propertyIndex) {
          SDOProperty declaredProperty = (SDOProperty) dataObject.getType().getDeclaredProperties().get(propertyIndex);
          Mapping mapping = this.getJAXBMappingForProperty(declaredProperty);
          if (declaredProperty.isMany()) {
              ContainerMapping containerMapping = (ContainerMapping) mapping;
              ContainerPolicy containerPolicy = containerMapping.getContainerPolicy();
  
              // OLD VALUE
              if (mapping.isAbstractCompositeCollectionMapping()) {
                  XMLCompositeCollectionMapping compositeMapping = (XMLCompositeCollectionMapping) mapping;
                  if (compositeMapping.getContainerAccessor() != null) {
  
                      Object oldContainer = mapping.getAttributeValueFromObject(entity);
                      if (oldContainer != null) {
                          AbstractSession session = ((JAXBContext) jaxbHelperContext.getJAXBContext()).getXMLContext().getSession(entity);
                          Object iterator = containerPolicy.iteratorFor(oldContainer);
                          while (containerPolicy.hasNext(iterator)) {
                              Object oldValue = containerPolicy.next(iterator, session);
                              compositeMapping.getContainerAccessor().setAttributeValueInObject(oldValue, null);
                          }
                      }
                  }
              }
  
              // NEW VALUE
              Object container = containerPolicy.containerInstance();
              mapping.getAttributeAccessor().setAttributeValueInObject(entity, container);
          } else {
              // OLD VALUE
              Object oldValue = mapping.getAttributeAccessor().getAttributeValueFromObject(entity);
              if (mapping.isAbstractCompositeObjectMapping()) {
                  XMLCompositeObjectMapping compositeMapping = (XMLCompositeObjectMapping) mapping;
                  if (compositeMapping.getContainerAccessor() != null) {
                      if (oldValue != null) {
                          compositeMapping.getContainerAccessor().setAttributeValueInObject(oldValue, null);
                      }
                  }
              }
  
              // NEW VALUE
              mapping.getAttributeAccessor().setAttributeValueInObject(entity, null);
          }
      }
  
      public Object getOpenContentProperty(Property property) {
          throw new UnsupportedOperationException();
      }
  
      public void setOpenContentProperty(Property property, Object value) {
          throw new UnsupportedOperationException();
      }
  
      public boolean isSetOpenContentProperty(Property property) {
  