/** INTERNAL: Return if the expression is for a direct mapped attribute. */
 public boolean isAttribute() {
   if (isAttributeExpression == null) {
     if (getSession() == null) {
       // We can't tell, so say no.
       return false;
     }
     QueryKey queryKey = getQueryKeyOrNull();
     if (queryKey != null) {
       isAttributeExpression = Boolean.valueOf(queryKey.isDirectQueryKey());
     } else {
       DatabaseMapping mapping = getMapping();
       if (mapping != null) {
         if (mapping.isVariableOneToOneMapping()) {
           throw QueryException.cannotQueryAcrossAVariableOneToOneMapping(
               mapping, mapping.getDescriptor());
         } else {
           isAttributeExpression = Boolean.valueOf(mapping.isDirectToFieldMapping());
         }
       } else {
         isAttributeExpression = Boolean.FALSE;
       }
     }
   }
   return isAttributeExpression.booleanValue();
 }
  /** INTERNAL: Transform the object-level value into a database-level value */
  public Object getFieldValue(Object objectValue, AbstractSession session) {
    DatabaseMapping mapping = getMapping();
    Object fieldValue = objectValue;
    if ((mapping != null)
        && (mapping.isDirectToFieldMapping() || mapping.isDirectCollectionMapping())) {
      // CR#3623207, check for IN Collection here not in mapping.
      if (objectValue instanceof Collection) {
        // This can actually be a collection for IN within expressions... however it would be better
        // for expressions to handle this.
        Collection values = (Collection) objectValue;
        Vector fieldValues = new Vector(values.size());
        for (Iterator iterator = values.iterator(); iterator.hasNext(); ) {
          Object value = iterator.next();
          if (!(value instanceof Expression)) {
            value = getFieldValue(value, session);
          }
          fieldValues.add(value);
        }
        fieldValue = fieldValues;
      } else {
        if (mapping.isDirectToFieldMapping()) {
          fieldValue = ((AbstractDirectMapping) mapping).getFieldValue(objectValue, session);
        } else if (mapping.isDirectCollectionMapping()) {
          fieldValue = ((DirectCollectionMapping) mapping).getFieldValue(objectValue, session);
        }
      }
    }

    return fieldValue;
  }
  /** INTERNAL: Find the alias for a given table */
  public DatabaseTable aliasForTable(DatabaseTable table) {
    DatabaseMapping mapping = getMapping();
    if (isAttribute()
        || ((mapping != null)
            && (mapping.isAggregateObjectMapping() || mapping.isTransformationMapping()))) {
      return ((DataExpression) getBaseExpression()).aliasForTable(table);
    }

    // "ref" and "structure" mappings, no table printed in the FROM clause, need to get the table
    // alias form the parent table
    if ((mapping != null) && (mapping.isReferenceMapping() || mapping.isStructureMapping())) {
      DatabaseTable alias =
          getBaseExpression().aliasForTable(mapping.getDescriptor().getTables().firstElement());
      alias.setName(alias.getName() + "." + mapping.getField().getName());
      return alias;
    }

    // For direct-collection mappings the alias is store on the table expression.
    if ((mapping != null) && (mapping.isDirectCollectionMapping())) {
      if (tableAliases != null) {
        DatabaseTable aliasedTable = tableAliases.keyAtValue(table);
        if (aliasedTable != null) {
          return aliasedTable;
        }
      }
      return getTable(table).aliasForTable(table);
    }

    return super.aliasForTable(table);
  }
  /** Do any required validation for this node. Throw an exception if it's incorrect. */
  public void validateNode() {
    if ((getQueryKeyOrNull() == null) && (getMapping() == null)) {
      throw QueryException.invalidQueryKeyInExpression(getName());
    }

    QueryKey queryKey = getQueryKeyOrNull();
    DatabaseMapping mapping = getMapping();

    Object theOneThatsNotNull = null;
    boolean qkIsToMany = false;
    if (queryKey != null) {
      theOneThatsNotNull = queryKey;
      qkIsToMany = queryKey.isManyToManyQueryKey() || queryKey.isOneToManyQueryKey();
    }
    boolean isNestedMapping = false;
    if (mapping != null) {
      // Bug 2847621 - Add Aggregate Collection to the list of valid items for outer join.
      if (shouldUseOuterJoin
          && (!(mapping.isOneToOneMapping()
              || mapping.isOneToManyMapping()
              || mapping.isManyToManyMapping()
              || mapping.isAggregateCollectionMapping()
              || mapping.isDirectCollectionMapping()))) {
        throw QueryException.outerJoinIsOnlyValidForOneToOneMappings(getMapping());
      }
      qkIsToMany = mapping.isCollectionMapping();
      if (index != null) {
        if (qkIsToMany) {
          CollectionMapping collectionMapping = (CollectionMapping) getMapping();
          if (collectionMapping.getListOrderField() != null) {
            index.setField(collectionMapping.getListOrderField());
            if (collectionMapping.shouldUseListOrderFieldTableExpression()) {
              Expression newBase = getTable(collectionMapping.getListOrderField().getTable());
              index.setBaseExpression(newBase);
            } else {
              addDerivedField(index);
            }
          } else {
            throw QueryException.indexRequiresCollectionMappingWithListOrderField(
                this, collectionMapping);
          }
        } else {
          throw QueryException.indexRequiresCollectionMappingWithListOrderField(this, mapping);
        }
      }
      isNestedMapping = mapping.isNestedTableMapping();
      theOneThatsNotNull = mapping;
    } else {
      if (index != null) {
        throw QueryException.indexRequiresCollectionMappingWithListOrderField(this, null);
      }
    }
    if ((!shouldQueryToManyRelationship()) && qkIsToMany && (!isNestedMapping)) {
      throw QueryException.invalidUseOfToManyQueryKeyInExpression(theOneThatsNotNull);
    }
    if (shouldQueryToManyRelationship() && !qkIsToMany) {
      throw QueryException.invalidUseOfAnyOfInExpression(theOneThatsNotNull);
    }
  }
 /** INTERNAL: Return all the fields */
 public Vector getFields() {
   if (isAttribute()) {
     Vector result = new Vector(1);
     DatabaseField field = getField();
     if (field != null) {
       result.addElement(field);
     }
     return result;
   } else {
     Vector result = new Vector();
     result.addAll(super.getFields());
     if (mapping.isCollectionMapping()) {
       List<DatabaseField> fields =
           mapping.getContainerPolicy().getAllFieldsForMapKey((CollectionMapping) mapping);
       if (fields != null) {
         result.addAll(fields);
       }
     }
     return result;
   }
 }
  /**
   * INTERNAL This method iterates through a collection and gets the values from the objects to
   * conform in an in-memory query. Creation date: (1/19/01 1:18:27 PM)
   */
  public Object valuesFromCollection(
      Object object, AbstractSession session, int valueHolderPolicy, boolean isObjectUnregistered) {
    // in case the mapping is null - this can happen if a query key is being used
    // In this case, check for the query key and find it's mapping.
    boolean readMappingFromQueryKey = false;
    if (getMapping() == null) {
      getMappingFromQueryKey();
      readMappingFromQueryKey = true;
    }

    // For bug 2780817 get the mapping directly from the object.  In EJB 2.0
    // inheritance, each child must override mappings defined in an abstract
    // class with its own.
    DatabaseMapping mapping = this.mapping;
    ClassDescriptor descriptor = mapping.getDescriptor();
    if (descriptor.hasInheritance() && (descriptor.getJavaClass() != object.getClass())) {
      mapping =
          session
              .getDescriptor(object.getClass())
              .getObjectBuilder()
              .getMappingForAttributeName(getName());
      descriptor = mapping.getDescriptor();
    }

    // fetch group support
    if (descriptor.hasFetchGroupManager()) {
      FetchGroupManager fetchGroupManager = descriptor.getFetchGroupManager();
      if (fetchGroupManager.isPartialObject(object)
          && (!fetchGroupManager.isAttributeFetched(object, mapping.getAttributeName()))) {
        // the conforming attribute is not fetched, simply throw exception
        throw QueryException.cannotConformUnfetchedAttribute(mapping.getAttributeName());
      }
    }

    if (mapping.isDirectToFieldMapping()) {
      return ((AbstractDirectMapping) mapping).valueFromObject(object, mapping.getField(), session);
    } else if (mapping.isForeignReferenceMapping()) {
      // CR 3677 integration of a ValueHolderPolicy
      Object valueFromMapping = mapping.getAttributeValueFromObject(object);
      if (!((ForeignReferenceMapping) mapping)
          .getIndirectionPolicy()
          .objectIsInstantiated(valueFromMapping)) {
        if (valueHolderPolicy != InMemoryQueryIndirectionPolicy.SHOULD_TRIGGER_INDIRECTION) {
          // If the client wishes us to trigger the indirection then we should do so,
          // Other wise throw the exception
          throw QueryException
              .mustInstantiateValueholders(); // you should instantiate the valueholder for this to
                                              // work
        }

        // maybe we should throw this exception from the start, to save time
      }
      Object valueToIterate = mapping.getRealAttributeValueFromObject(object, session);
      UnitOfWorkImpl uow = isObjectUnregistered ? (UnitOfWorkImpl) session : null;

      // First check that object in fact is unregistered.
      // toDo: ?? Why is this commented out? Why are we supporting the unregistered thing at all?
      // Does not seem to be any public API for this, nor every used internally?
      // if (isObjectUnregistered) {
      //	isObjectUnregistered = !uow.getCloneMapping().containsKey(object);
      // }
      if (mapping.isCollectionMapping() && (valueToIterate != null)) {
        // For bug 2766379 must use the correct version of vectorFor to
        // unwrap the result same time.
        valueToIterate = mapping.getContainerPolicy().vectorFor(valueToIterate, session);

        // toDo: If the value is empty, need to support correct inner/outer join filtering
        // symantics.
        // For CR 2612601, try to partially replace the result with already
        // registered objects.
        if (isObjectUnregistered && (uow.getCloneMapping().get(object) == null)) {
          Vector objectValues = (Vector) valueToIterate;
          for (int i = 0; i < objectValues.size(); i++) {
            Object original = objectValues.elementAt(i);
            Object clone =
                uow.getIdentityMapAccessorInstance()
                    .getIdentityMapManager()
                    .getFromIdentityMap(original);
            if (clone != null) {
              objectValues.setElementAt(clone, i);
            }
          }
        }

        // For CR 2612601, conforming without registering, a query could be
        // bob.get("address").get("city").equal("Ottawa"); where the address
        // has been registered and modified in the UOW, but bob has not.  Thus
        // even though bob does not point to the modified address now, it will
        // as soon as it is registered, so should point to it here.
      } else if (isObjectUnregistered && (uow.getCloneMapping().get(object) == null)) {
        Object clone =
            uow.getIdentityMapAccessorInstance()
                .getIdentityMapManager()
                .getFromIdentityMap(valueToIterate);
        if (clone != null) {
          valueToIterate = clone;
        }
      }
      return valueToIterate;
    } else if (mapping.isAggregateMapping()) {
      Object aggregateValue = mapping.getAttributeValueFromObject(object);
      // Bug 3995468 - if this query key is to a mapping in an aggregate object, get the object from
      // actual mapping rather than the aggregate mapping
      while (readMappingFromQueryKey
          && mapping.isAggregateObjectMapping()
          && !((AggregateObjectMapping) mapping)
              .getReferenceClass()
              .equals(queryKey.getDescriptor().getJavaClass())) {
        mapping =
            mapping
                .getReferenceDescriptor()
                .getObjectBuilder()
                .getMappingForField(((DirectQueryKey) queryKey).getField());
        aggregateValue = mapping.getRealAttributeValueFromObject(aggregateValue, session);
      }
      return aggregateValue;
    } else {
      throw QueryException.cannotConformExpression();
    }
  }
 /**
  * INTERNAL: Return any additional tables that belong to this expression An example of how this
  * method is used is to return any tables that belong to the map key when this expression
  * traverses a mapping that uses a Map
  */
 public List<DatabaseTable> getAdditionalTables() {
   if (mapping != null && mapping.isCollectionMapping()) {
     return ((CollectionMapping) mapping).getContainerPolicy().getAdditionalTablesForJoinQuery();
   }
   return null;
 }