/**
   * INTERNAL: Return the value of the field from the row or a value holder on the query to obtain
   * the object. Check for batch + aggregation reading.
   */
  @Override
  public Object valueFromRow(
      AbstractRecord row,
      JoinedAttributeManager joinManager,
      ObjectBuildingQuery sourceQuery,
      AbstractSession executionSession)
      throws DatabaseException {
    // If any field in the foreign key is null then it means there are no referenced objects
    for (Enumeration enumeration = getFields().elements(); enumeration.hasMoreElements(); ) {
      DatabaseField field = (DatabaseField) enumeration.nextElement();
      if (row.get(field) == null) {
        return getIndirectionPolicy().nullValueFromRow();
      }
    }

    if (getTypeField() != null) {
      // If the query used batched reading, return a special value holder,
      // or retrieve the object from the query property.
      if (sourceQuery.isReadAllQuery()
          && (((ReadAllQuery) sourceQuery).isAttributeBatchRead(getDescriptor(), getAttributeName())
              || shouldUseBatchReading())) {
        return batchedValueFromRow(row, ((ReadAllQuery) sourceQuery));
      }

      // If the field is empty we cannot load the object because we do not know what class it will
      // be
      if (row.get(getTypeField()) == null) {
        return getIndirectionPolicy().nullValueFromRow();
      }
      Class implementerClass =
          (Class) getImplementorForType(row.get(getTypeField()), executionSession);
      ReadObjectQuery query = (ReadObjectQuery) getSelectionQuery().clone();
      query.setReferenceClass(implementerClass);
      query.setSelectionCriteria(getSelectionCriteria());
      query.setDescriptor(null); // Must set to null so the right descriptor is used

      if (sourceQuery.isObjectLevelReadQuery()
          && (sourceQuery.shouldCascadeAllParts()
              || (sourceQuery.shouldCascadePrivateParts() && isPrivateOwned())
              || (sourceQuery.shouldCascadeByMapping() && this.cascadeRefresh))) {
        query.setShouldRefreshIdentityMapResult(sourceQuery.shouldRefreshIdentityMapResult());
        query.setCascadePolicy(sourceQuery.getCascadePolicy());
        query.setShouldMaintainCache(sourceQuery.shouldMaintainCache());
        // For flashback.
        if (((ObjectLevelReadQuery) sourceQuery).hasAsOfClause()) {
          query.setAsOfClause(((ObjectLevelReadQuery) sourceQuery).getAsOfClause());
        }

        // CR #4365 - used to prevent infinit recursion on refresh object cascade all
        query.setQueryId(sourceQuery.getQueryId());
      }

      return getIndirectionPolicy().valueFromQuery(query, row, executionSession);
    } else {
      return super.valueFromRow(row, joinManager, sourceQuery, executionSession);
    }
  }
 /**
  * INTERNAL: Extract the primary key values from the row, then create an
  * org.eclipse.persistence.internal.oxm.Reference instance and stored it on the session's
  * org.eclipse.persistence.internal.oxm.ReferenceResolver.
  */
 public Object readFromRowIntoObject(
     AbstractRecord databaseRow,
     JoinedAttributeManager joinManager,
     Object targetObject,
     ObjectBuildingQuery sourceQuery,
     AbstractSession executionSession)
     throws DatabaseException {
   ClassDescriptor descriptor = sourceQuery.getSession().getClassDescriptor(getReferenceClass());
   ContainerPolicy cp = this.getContainerPolicy();
   Vector pkFieldNames = referenceDescriptor.getPrimaryKeyFieldNames();
   Vector primaryKeyValues = new Vector();
   primaryKeyValues.setSize(pkFieldNames.size());
   HashMap primaryKeyMap = new HashMap();
   // for each source xmlField, get the value from the row and store
   for (Iterator fieldIt = getFields().iterator(); fieldIt.hasNext(); ) {
     XMLField fld = (XMLField) fieldIt.next();
     XMLField tgtFld = (XMLField) getSourceToTargetKeyFieldAssociations().get(fld);
     Object fieldValue = databaseRow.getValues(fld);
     if ((fieldValue == null)
         || (fieldValue instanceof String)
         || !(fieldValue instanceof Vector)) {
       return cp.containerInstance();
     }
     // fix for bug# 5687430
     // need to get the actual type of the target (i.e. int, String, etc.)
     // and use the converted value when checking the cache.
     XMLConversionManager xmlConversionManager =
         (XMLConversionManager) executionSession.getDatasourcePlatform().getConversionManager();
     Vector newValues = new Vector();
     for (Iterator valIt = ((Vector) fieldValue).iterator(); valIt.hasNext(); ) {
       for (StringTokenizer stok = new StringTokenizer((String) valIt.next());
           stok.hasMoreTokens(); ) {
         Object value =
             xmlConversionManager.convertObject(
                 stok.nextToken(), descriptor.getTypedField(tgtFld).getType());
         if (value != null) {
           newValues.add(value);
         }
       }
     }
     primaryKeyMap.put(tgtFld.getXPath(), newValues);
   }
   // store the Reference instance on the resolver for use during mapping resolution phase
   ReferenceResolver resolver = ReferenceResolver.getInstance(sourceQuery.getSession());
   if (resolver != null) {
     resolver.addReference(new Reference(this, targetObject, referenceClass, primaryKeyMap));
   }
   return null;
 }
 @Override
 protected Object buildCompositeObject(
     ClassDescriptor descriptor,
     AbstractRecord nestedRow,
     ObjectBuildingQuery query,
     CacheKey parentCacheKey,
     JoinedAttributeManager joinManager,
     AbstractSession targetSession) {
   Object element = descriptor.getObjectBuilder().buildNewInstance();
   descriptor
       .getObjectBuilder()
       .buildAttributesIntoObject(
           element,
           parentCacheKey,
           nestedRow,
           query,
           joinManager,
           query.getExecutionFetchGroup(descriptor),
           false,
           targetSession);
   return element;
 }
  /**
   * INTERNAL: Return the value of the reference attribute or a value holder. Check whether the
   * mapping's attribute should be optimized through batch and joining.
   */
  public Object valueFromRow(
      AbstractRecord row,
      JoinedAttributeManager joinManager,
      ObjectBuildingQuery sourceQuery,
      AbstractSession executionSession)
      throws DatabaseException {
    if (((EISDescriptor) this.getDescriptor()).getDataFormat() == EISDescriptor.XML) {
      ((XMLRecord) row).setSession(executionSession);
    }

    ReadQuery targetQuery = getSelectionQuery();
    if (!isForeignKeyRelationship) {
      // if the source query is cascading then the target query must use the same settings
      if (targetQuery.isObjectLevelReadQuery()
          && (sourceQuery.shouldCascadeAllParts()
              || (sourceQuery.shouldCascadePrivateParts() && isPrivateOwned())
              || (sourceQuery.shouldCascadeByMapping() && this.cascadeRefresh))) {
        targetQuery = (ObjectLevelReadQuery) targetQuery.clone();
        ((ObjectLevelReadQuery) targetQuery)
            .setShouldRefreshIdentityMapResult(sourceQuery.shouldRefreshIdentityMapResult());
        targetQuery.setCascadePolicy(sourceQuery.getCascadePolicy());
        // CR #4365
        targetQuery.setQueryId(sourceQuery.getQueryId());
        // For queries that have turned caching off, such as aggregate collection, leave it off.
        if (targetQuery.shouldMaintainCache()) {
          targetQuery.setShouldMaintainCache(sourceQuery.shouldMaintainCache());
        }
      }

      return getIndirectionPolicy().valueFromQuery(targetQuery, row, sourceQuery.getSession());
    } else {
      if (getIndirectionPolicy().usesIndirection()) {
        EISOneToManyQueryBasedValueHolder valueholder =
            new EISOneToManyQueryBasedValueHolder(this, targetQuery, row, sourceQuery.getSession());
        return valueholder;
      } else {
        Vector subRows = getForeignKeyRows(row);

        if (subRows == null) {
          return null;
        }

        ContainerPolicy cp = this.getContainerPolicy();
        Object results = cp.containerInstance(subRows.size());

        for (int i = 0; i < subRows.size(); i++) {
          XMLRecord subRow = (XMLRecord) subRows.elementAt(i);
          subRow.setSession(executionSession);
          Object object =
              getIndirectionPolicy().valueFromQuery(targetQuery, subRow, sourceQuery.getSession());
          if (object instanceof Collection) {
            java.util.Iterator iter = ((Collection) object).iterator();
            while (iter.hasNext()) {
              cp.addInto(iter.next(), results, executionSession);
            }
          } else if (object instanceof java.util.Map) {
            java.util.Iterator iter = ((java.util.Map) object).values().iterator();
            while (iter.hasNext()) {
              cp.addInto(iter.next(), results, executionSession);
            }
          } else {
            cp.addInto(object, results, executionSession);
          }
        }
        if (cp.sizeFor(results) == 0) {
          return null;
        }
        return results;
      }
    }
  }
  public Object valueFromRow(
      AbstractRecord row,
      JoinedAttributeManager joinManager,
      ObjectBuildingQuery sourceQuery,
      CacheKey cacheKey,
      AbstractSession executionSession,
      boolean isTargetProtected,
      Boolean[] wasCacheUsed)
      throws DatabaseException {
    ContainerPolicy cp = this.getContainerPolicy();

    Object fieldValue = row.getValues(this.getField());

    // BUG#2667762 there could be whitespace in the row instead of null
    if ((fieldValue == null) || (fieldValue instanceof String)) {
      if (reuseContainer) {
        Object currentObject = ((XMLRecord) row).getCurrentObject();
        Object container = getAttributeAccessor().getAttributeValueFromObject(currentObject);
        return container != null ? container : cp.containerInstance();
      } else {
        return cp.containerInstance();
      }
    }

    Vector nestedRows =
        this.getDescriptor().buildNestedRowsFromFieldValue(fieldValue, executionSession);
    if (nestedRows == null) {
      if (reuseContainer) {
        Object currentObject = ((XMLRecord) row).getCurrentObject();
        Object container = getAttributeAccessor().getAttributeValueFromObject(currentObject);
        return container != null ? container : cp.containerInstance();
      } else {
        return cp.containerInstance();
      }
    }

    Object result = null;
    if (reuseContainer) {
      Object currentObject = ((XMLRecord) row).getCurrentObject();
      Object container = getAttributeAccessor().getAttributeValueFromObject(currentObject);
      result = container != null ? container : cp.containerInstance();
    } else {
      result = cp.containerInstance(nestedRows.size());
    }

    for (Enumeration stream = nestedRows.elements(); stream.hasMoreElements(); ) {
      XMLRecord nestedRow = (XMLRecord) stream.nextElement();
      Object objectToAdd;
      if (getNullPolicy().valueIsNull((Element) nestedRow.getDOM())) {
        objectToAdd = null;
      } else {
        objectToAdd =
            buildObjectFromNestedRow(
                nestedRow, joinManager, sourceQuery, executionSession, isTargetProtected);
      }
      cp.addInto(objectToAdd, result, sourceQuery.getSession());
      if (null != getContainerAccessor()) {
        Object currentObject = ((XMLRecord) row).getCurrentObject();
        if (this.inverseReferenceMapping.getContainerPolicy() == null) {
          getContainerAccessor().setAttributeValueInObject(objectToAdd, currentObject);
        } else {
          Object backpointerContainer =
              getContainerAccessor().getAttributeValueFromObject(objectToAdd);
          if (backpointerContainer == null) {
            backpointerContainer =
                this.inverseReferenceMapping.getContainerPolicy().containerInstance();
            getContainerAccessor().setAttributeValueInObject(objectToAdd, backpointerContainer);
          }
          this.inverseReferenceMapping
              .getContainerPolicy()
              .addInto(currentObject, backpointerContainer, executionSession);
        }
      }
    }
    return result;
  }
  public Object valueFromRow(
      AbstractRecord row,
      JoinedAttributeManager joinManager,
      ObjectBuildingQuery query,
      AbstractSession executionSession) {
    ContainerPolicy cp = this.getContainerPolicy();

    Object fieldValue = row.getValues(this.getField());
    if (fieldValue == null) {
      if (reuseContainer) {
        Object currentObject = ((XMLRecord) row).getCurrentObject();
        Object container = getAttributeAccessor().getAttributeValueFromObject(currentObject);
        return container != null ? container : cp.containerInstance();
      } else {
        return cp.containerInstance();
      }
    }

    Vector fieldValues = this.getDescriptor().buildDirectValuesFromFieldValue(fieldValue);
    if (fieldValues == null) {
      if (reuseContainer) {
        Object currentObject = ((XMLRecord) row).getCurrentObject();
        Object container = getAttributeAccessor().getAttributeValueFromObject(currentObject);
        return container != null ? container : cp.containerInstance();
      } else {
        return cp.containerInstance();
      }
    }

    Object result = null;
    if (reuseContainer) {
      Object currentObject = ((XMLRecord) row).getCurrentObject();
      Object container = getAttributeAccessor().getAttributeValueFromObject(currentObject);
      result = container != null ? container : cp.containerInstance();
    } else {
      result = cp.containerInstance(fieldValues.size());
    }

    for (Enumeration stream = fieldValues.elements(); stream.hasMoreElements(); ) {
      Object element = stream.nextElement();

      // PERF: Direct variable access.
      // Object value = row.get(field);
      // Object fieldValue = null;
      XMLUnmarshaller unmarshaller = ((XMLRecord) row).getUnmarshaller();
      if (element instanceof String) {
        if (this.isSwaRef() && (unmarshaller.getAttachmentUnmarshaller() != null)) {
          fieldValue =
              unmarshaller.getAttachmentUnmarshaller().getAttachmentAsDataHandler((String) element);
        } else if (!this.isSwaRef()) {
          // should be base64
          byte[] bytes =
              ((XMLConversionManager)
                      executionSession.getDatasourcePlatform().getConversionManager())
                  .convertSchemaBase64ToByteArray(element);
          fieldValue = bytes;
        }
      } else {
        // this was an element, so do the XOP/SWAREF/Inline binary cases for an element
        XMLRecord record = (XMLRecord) element;
        record.setSession(executionSession);

        if ((unmarshaller.getAttachmentUnmarshaller() != null)
            && unmarshaller.getAttachmentUnmarshaller().isXOPPackage()
            && !this.isSwaRef()
            && !this.shouldInlineBinaryData()) {
          // look for the include element:
          String xpath = XMLConstants.EMPTY_STRING;

          //  need a prefix for XOP
          String prefix = null;
          NamespaceResolver descriptorResolver =
              ((XMLDescriptor) getDescriptor()).getNamespaceResolver();
          if (descriptorResolver != null) {
            prefix = descriptorResolver.resolveNamespaceURI(XMLConstants.XOP_URL);
          }
          if (prefix == null) {
            prefix = XMLConstants.XOP_PREFIX;
          }
          NamespaceResolver tempResolver = new NamespaceResolver();
          tempResolver.put(prefix, XMLConstants.XOP_URL);
          xpath = prefix + XMLConstants.COLON + INCLUDE + "/@href";
          XMLField field = new XMLField(xpath);
          field.setNamespaceResolver(tempResolver);
          String includeValue = (String) record.get(field);
          if (element != null && includeValue != null) {
            if ((getAttributeElementClass() == ClassConstants.ABYTE)
                || (getAttributeElementClass() == ClassConstants.APBYTE)) {
              fieldValue =
                  unmarshaller.getAttachmentUnmarshaller().getAttachmentAsByteArray(includeValue);
            } else {
              fieldValue =
                  unmarshaller.getAttachmentUnmarshaller().getAttachmentAsDataHandler(includeValue);
            }
          } else {
            // If we didn't find the Include element, check for inline
            fieldValue = record.get(XMLConstants.TEXT);
            // should be a base64 string
            fieldValue =
                ((XMLConversionManager)
                        executionSession.getDatasourcePlatform().getConversionManager())
                    .convertSchemaBase64ToByteArray(fieldValue);
          }
        } else if ((unmarshaller.getAttachmentUnmarshaller() != null) && isSwaRef()) {
          String refValue = (String) record.get(XMLConstants.TEXT);
          if (refValue != null) {
            fieldValue =
                unmarshaller.getAttachmentUnmarshaller().getAttachmentAsDataHandler(refValue);
          }
        } else {
          fieldValue = record.get(XMLConstants.TEXT);
          // should be a base64 string
          fieldValue =
              ((XMLConversionManager)
                      executionSession.getDatasourcePlatform().getConversionManager())
                  .convertSchemaBase64ToByteArray(fieldValue);
        }
      }
      Object attributeValue = fieldValue;
      if (getValueConverter() != null) {
        if (getValueConverter() instanceof XMLConverter) {
          attributeValue =
              ((XMLConverter) getValueConverter())
                  .convertDataValueToObjectValue(fieldValue, executionSession, unmarshaller);
        } else {
          attributeValue =
              getValueConverter().convertDataValueToObjectValue(fieldValue, executionSession);
        }
      }

      cp.addInto(attributeValue, result, query.getSession());
    }
    return result;
  }