/**
   * INTERNAL Return the descriptor which contains this query key, look in the inheritance hierarchy
   * of rootDescriptor for the descriptor.
   */
  public ClassDescriptor convertToCastDescriptor(
      ClassDescriptor rootDescriptor, AbstractSession session) {
    if (castClass == null || rootDescriptor == null || rootDescriptor.getJavaClass() == castClass) {
      return rootDescriptor;
    }

    ClassDescriptor castDescriptor = session.getClassDescriptor(castClass);

    if (castDescriptor == null) {
      throw QueryException.couldNotFindCastDescriptor(castClass, getBaseExpression());
    }
    if (!castDescriptor.hasInheritance()) {
      throw QueryException.castMustUseInheritance(getBaseExpression());
    }
    ClassDescriptor parentDescriptor = castDescriptor.getInheritancePolicy().getParentDescriptor();
    while (parentDescriptor != null) {
      if (parentDescriptor == rootDescriptor) {
        return castDescriptor;
      }
      parentDescriptor = parentDescriptor.getInheritancePolicy().getParentDescriptor();
    }

    ClassDescriptor childDescriptor = rootDescriptor;
    while (childDescriptor != null) {
      if (childDescriptor == castDescriptor) {
        return rootDescriptor;
      }
      childDescriptor = childDescriptor.getInheritancePolicy().getParentDescriptor();
    }

    throw QueryException.couldNotFindCastDescriptor(castClass, getBaseExpression());
  }
  /**
   * INTERNAL - Return the descriptor which contains this query key, look in the inheritance
   * hierarchy of rootDescriptor for the descriptor. Does not set the descriptor, only returns it.
   */
  public ClassDescriptor convertToCastDescriptor(
      ClassDescriptor rootDescriptor, AbstractSession session) {
    isDowncast = Boolean.FALSE;
    if (castClass == null || rootDescriptor == null || rootDescriptor.getJavaClass() == castClass) {
      return rootDescriptor;
    }

    ClassDescriptor castDescriptor = session.getClassDescriptor(castClass);

    if (castDescriptor == null) {
      throw QueryException.couldNotFindCastDescriptor(castClass, getBaseExpression());
    }
    if (!castDescriptor.hasInheritance()) {
      throw QueryException.castMustUseInheritance(getBaseExpression());
    }
    ClassDescriptor parentDescriptor = castDescriptor.getInheritancePolicy().getParentDescriptor();
    while (parentDescriptor != null) {
      if (parentDescriptor == rootDescriptor) {
        isDowncast = Boolean.TRUE;
        return castDescriptor;
      }
      parentDescriptor = parentDescriptor.getInheritancePolicy().getParentDescriptor();
    }
    // is there value casting an emp to person in a query?
    ClassDescriptor childDescriptor = rootDescriptor;
    while (childDescriptor != null) {
      if (childDescriptor == castDescriptor) {
        return rootDescriptor;
      }
      childDescriptor = childDescriptor.getInheritancePolicy().getParentDescriptor();
    }

    throw QueryException.couldNotFindCastDescriptor(castClass, getBaseExpression());
  }
  /**
   * INTERNAL Return true if it uses a cast class and query is downcasting. It will look into
   * inheritance hierarchy of the root descriptor.
   */
  public boolean isDowncast(ClassDescriptor rootDescriptor, AbstractSession session) {
    if (castClass == null) {
      return false;
    }

    if (rootDescriptor.getJavaClass() == castClass) {
      return false;
    }

    ClassDescriptor castDescriptor = session.getClassDescriptor(castClass);

    if (castDescriptor == null) {
      throw QueryException.couldNotFindCastDescriptor(castClass, getBaseExpression());
    }
    if (castDescriptor.getInheritancePolicy() == null) {
      throw QueryException.castMustUseInheritance(getBaseExpression());
    }
    ClassDescriptor parentDescriptor = castDescriptor.getInheritancePolicy().getParentDescriptor();
    while (parentDescriptor != null) {
      if (parentDescriptor == rootDescriptor) {
        return true;
      }
      parentDescriptor = parentDescriptor.getInheritancePolicy().getParentDescriptor();
    }

    throw QueryException.couldNotFindCastDescriptor(castClass, getBaseExpression());
  }
  /**
   * INTERNAL: Create (if necessary) and populate a reference object that will be used during the
   * mapping reference resolution phase after unmarshalling is complete.
   *
   * @param record
   * @param xmlField
   * @param object
   * @param session
   * @return
   */
  public void buildReference(
      UnmarshalRecord record, XMLField xmlField, Object object, AbstractSession session) {
    ReferenceResolver resolver = ReferenceResolver.getInstance(session);
    if (resolver == null) {
      return;
    }

    Object srcObject = record.getCurrentObject();
    Reference reference = resolver.getReference(this, srcObject);
    // if reference is null, create a new instance and set it on the resolver
    if (reference == null) {
      reference = new Reference(this, srcObject, getReferenceClass(), new HashMap());
      resolver.addReference(reference);
    }

    XMLField tgtFld = (XMLField) getSourceToTargetKeyFieldAssociations().get(xmlField);
    String tgtXPath = tgtFld.getXPath();
    Vector pks;
    HashMap primaryKeyMap = reference.getPrimaryKeyMap();
    if (primaryKeyMap.containsKey(tgtXPath)) {
      pks = (Vector) primaryKeyMap.get(tgtXPath);
    } else {
      pks = new Vector();
      primaryKeyMap.put(tgtXPath, pks);
    }

    ClassDescriptor descriptor = session.getClassDescriptor(getReferenceClass());
    Class type = descriptor.getTypedField(tgtFld).getType();
    XMLConversionManager xmlConversionManager =
        (XMLConversionManager) session.getDatasourcePlatform().getConversionManager();
    for (StringTokenizer stok = new StringTokenizer((String) object); stok.hasMoreTokens(); ) {
      Object value = xmlConversionManager.convertObject(stok.nextToken(), type);
      if (value != null) {
        pks.add(value);
      }
    }
  }