/**
  * INTERNAL: this returns a single expression to represent the join from the main table to all
  * child descriptor tables Only if outer joins should be printed in the where clause
  *
  * @return Expression
  */
 public Expression getTreatCriteria() {
   if (getDescriptor() == null) {
     return null;
   }
   // need to build this using just the multiple tables on this descriptor not included in the
   // parent's join expression
   Expression criteria = null;
   if (getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
     Vector tables = getDescriptor().getTables(); // This child's tables
     ClassDescriptor parentDescriptor = this.typeExpressionBase.getDescriptor();
     int tablesSize = tables.size();
     if (parentDescriptor.hasInheritance()
         && parentDescriptor.getInheritancePolicy().hasMultipleTableChild()) {
       // look up the joins from the parent descriptor to our tables.
       for (int i = 0; i < tablesSize; i++) {
         DatabaseTable table = (DatabaseTable) tables.elementAt(i);
         Expression joinExpression =
             parentDescriptor.getInheritancePolicy().getChildrenTablesJoinExpressions().get(table);
         // Some of our tables might be the in our parent as well, so ignore the lack of a
         // joinExpression
         if (joinExpression != null) {
           joinExpression = this.baseExpression.twist(joinExpression, this);
           if (shouldUseOuterJoin()) {
             joinExpression = joinExpression.convertToUseOuterJoin();
           }
           criteria = joinExpression.and(criteria);
         }
       }
     }
   }
   return criteria;
 }
 /** INTERNAL: */
 @Override
 public List<DatabaseField> getSelectionFields(ReadQuery query) {
   if (getDescriptor() == null) {
     DatabaseMapping mapping = getMapping();
     if (mapping != null) {
       return mapping.getSelectFields();
     }
     return new ArrayList<DatabaseField>(0);
   }
   if (descriptor.hasInheritance()
           && descriptor.getInheritancePolicy().shouldReadSubclasses()
           && (!descriptor.getInheritancePolicy().hasMultipleTableChild())
       || shouldUseOuterJoinForMultitableInheritance()) {
     // return all fields because we can.
     if (query != null && query.isObjectLevelReadQuery()) {
       return descriptor.getAllSelectionFields((ObjectLevelReadQuery) query);
     } else {
       return descriptor.getAllSelectionFields();
     }
   } else {
     if (query != null && query.isObjectLevelReadQuery()) {
       return descriptor.getSelectionFields((ObjectLevelReadQuery) query);
     } else {
       return descriptor.getSelectionFields();
     }
   }
 }
  /**
   * 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());
  }
 /**
  * Return whether the reference objects must be deleted one by one, as opposed to with a single
  * DELETE statement.
  */
 protected boolean mustDeleteReferenceObjectsOneByOne() {
   ClassDescriptor referenceDescriptor = this.getReferenceDescriptor();
   return referenceDescriptor.hasDependencyOnParts()
       || referenceDescriptor.usesOptimisticLocking()
       || (referenceDescriptor.hasInheritance()
           && referenceDescriptor.getInheritancePolicy().shouldReadSubclasses())
       || referenceDescriptor.hasMultipleTables();
 }
  /**
   * INTERNAL: much like getOwnedTables(), this gets the tables represented from the descriptor.
   * Difference is this only returns local tables for the child casted descriptor, and excludes
   * tables owned by the parent descriptor
   */
  public List<DatabaseTable> getOwnedSubTables() {
    ClassDescriptor parentDescriptor = this.typeExpressionBase.getDescriptor();
    Vector<DatabaseTable> childTables = new Vector(2);
    if (parentDescriptor.hasInheritance()
        && parentDescriptor.getInheritancePolicy().hasMultipleTableChild()) {
      List parentTables = typeExpressionBase.getOwnedTables();
      // All tables for this child, including parent tables
      Vector<DatabaseTable> tables = getDescriptor().getTables();
      for (DatabaseTable table : tables) {
        if (!parentTables.contains(table)) {
          childTables.add(table);
        }
      }
    }

    return childTables;
  }
 /**
  * INTERNAL: Not to be confused with the public getField(String) This returns a collection of all
  * fields associated with this object. Really only applies to query keys representing an object or
  * to expression builders.
  */
 @Override
 public Vector getFields() {
   if (getDescriptor() == null) {
     DatabaseMapping mapping = getMapping();
     if (mapping != null) {
       return mapping.getSelectFields();
     }
     return new NonSynchronizedVector(0);
   }
   if (descriptor.hasInheritance()
           && descriptor.getInheritancePolicy().shouldReadSubclasses()
           && (!descriptor.getInheritancePolicy().hasMultipleTableChild())
       || shouldUseOuterJoinForMultitableInheritance()) {
     // return all fields because we can.
     return descriptor.getAllFields();
   } else {
     return descriptor.getFields();
   }
 }
  /**
   * INTERNAL: Used in case outer joins should be printed in FROM clause. Each of the additional
   * tables mapped to expressions that joins it.
   */
  public Map additionalTreatExpressionCriteriaMap() {
    if (getDescriptor() == null) {
      return null;
    }
    int tableSize = 0;
    HashMap tablesJoinExpressions = new HashMap();

    ClassDescriptor parentDescriptor = this.typeExpressionBase.getDescriptor();

    // outerjoin our parent->child tables
    if (parentDescriptor.hasInheritance()
        && parentDescriptor.getInheritancePolicy().hasMultipleTableChild()) {
      Vector tables = getDescriptor().getTables(); // All this child's tables
      tableSize = tables.size();
      // look up the joins from the parent descriptor to our tables.
      for (int i = 0; i < tableSize; i++) {
        DatabaseTable table = (DatabaseTable) tables.elementAt(i);
        Expression joinExpression =
            parentDescriptor.getInheritancePolicy().getChildrenTablesJoinExpressions().get(table);
        // Some of our tables might be the in our parent as well, so ignore the lack of a
        // joinExpression
        if (joinExpression != null) {
          joinExpression = this.baseExpression.twist(joinExpression, this);
          tablesJoinExpressions.put(table, joinExpression);
        }
      }
    }

    if (isUsingOuterJoinForMultitableInheritance()) {
      List childrenTables = getDescriptor().getInheritancePolicy().getChildrenTables();
      tableSize = childrenTables.size();
      for (int i = 0; i < tableSize; i++) {
        DatabaseTable table = (DatabaseTable) childrenTables.get(i);
        Expression joinExpression =
            getDescriptor().getInheritancePolicy().getChildrenTablesJoinExpressions().get(table);
        joinExpression = this.baseExpression.twist(joinExpression, this);
        tablesJoinExpressions.put(table, joinExpression);
      }
    }

    return tablesJoinExpressions;
  }
 public static Hashtable buildInheritanceHierarchyTree(Project project) {
   Map descriptors = project.getDescriptors();
   Hashtable hierarchyTree = new Hashtable(descriptors.size());
   for (Iterator descriptorIterator = descriptors.values().iterator();
       descriptorIterator.hasNext(); ) {
     ClassDescriptor descriptor = (ClassDescriptor) descriptorIterator.next();
     String className = descriptor.getJavaClassName();
     if (className == null) {
       className = descriptor.getJavaClass().getName();
     }
     HierarchyNode node = getNodeForClass(className, hierarchyTree);
     if (descriptor.hasInheritance()
         && (descriptor.getInheritancePolicy().getParentClassName() != null)) {
       HierarchyNode parentNode =
           getNodeForClass(descriptor.getInheritancePolicy().getParentClassName(), hierarchyTree);
       node.setParent(parentNode);
     }
   }
   return hierarchyTree;
 }
 protected Object readObjectFromRow(Session session, ClassDescriptor desc, Record row) {
   if (desc.hasInheritance()) {
     Class newClass =
         desc.getInheritancePolicy().classFromRow((DatabaseRecord) row, (AbstractSession) session);
     desc = session.getClassDescriptor(newClass);
   }
   Object object = desc.getObjectBuilder().buildNewInstance();
   ReadObjectQuery query = new ReadObjectQuery();
   query.setSession((AbstractSession) session);
   for (Enumeration mappings = desc.getMappings().elements(); mappings.hasMoreElements(); ) {
     DatabaseMapping mapping = (DatabaseMapping) mappings.nextElement();
     mapping.readFromRowIntoObject(
         (DatabaseRecord) row,
         query.getJoinedAttributeManager(),
         object,
         null,
         query,
         query.getSession(),
         true);
   }
   return object;
 }
  /**
   * 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();
    }
  }
  public Object buildObjectFromNestedRow(
      AbstractRecord nestedRow,
      JoinedAttributeManager joinManager,
      ObjectBuildingQuery sourceQuery,
      AbstractSession executionSession,
      boolean isTargetProtected) {
    Object objectToAdd = null;
    ClassDescriptor aDescriptor = getReferenceDescriptor((DOMRecord) nestedRow);

    if (aDescriptor == null) {
      if ((getKeepAsElementPolicy() == UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT)
          || (getKeepAsElementPolicy() == UnmarshalKeepAsElementPolicy.KEEP_ALL_AS_ELEMENT)) {
        XMLPlatformFactory.getInstance()
            .getXMLPlatform()
            .namespaceQualifyFragment((Element) ((DOMRecord) nestedRow).getDOM());
        objectToAdd = ((DOMRecord) nestedRow).getDOM();
        convertDataValueToObjectValue(
            objectToAdd, executionSession, ((XMLRecord) nestedRow).getUnmarshaller());
        // simple case
        objectToAdd = convertToSimpleTypeIfPresent(objectToAdd, nestedRow, executionSession);
      } else {
        NodeList children = ((Element) ((DOMRecord) nestedRow).getDOM()).getChildNodes();
        for (int i = 0; i < children.getLength(); i++) {
          Node nextNode = children.item(i);
          if (nextNode.getNodeType() == nextNode.ELEMENT_NODE) {
            // complex child
            String type =
                ((Element) ((DOMRecord) nestedRow).getDOM())
                    .getAttributeNS(
                        javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI,
                        XMLConstants.SCHEMA_TYPE_ATTRIBUTE);
            if (type != null && type.length() > 0) {
              throw XMLMarshalException.unknownXsiTypeValue(type, (Mapping) this);
            } else {
              throw XMLMarshalException.noDescriptorFound((Mapping) this);
            }
          }
        }
        // simple case
        objectToAdd = convertToSimpleTypeIfPresent(objectToAdd, nestedRow, executionSession);
      }
    } else {
      if (aDescriptor.hasInheritance()) {
        Class newElementClass =
            aDescriptor.getInheritancePolicy().classFromRow(nestedRow, executionSession);
        if (newElementClass == null) {
          // no xsi:type attribute - look for type indicator on the field
          QName leafElementType = ((XMLField) getField()).getLeafElementType();
          if (leafElementType != null) {
            XPathQName leafElementXPathQName =
                new XPathQName(leafElementType, ((XMLRecord) nestedRow).isNamespaceAware());
            Object indicator =
                aDescriptor
                    .getInheritancePolicy()
                    .getClassIndicatorMapping()
                    .get(leafElementXPathQName);
            if (indicator != null) {
              newElementClass = (Class) indicator;
            }
          }
        }
        if (newElementClass != null) {
          aDescriptor = this.getReferenceDescriptor(newElementClass, executionSession);
        } else {
          // since there is no xsi:type attribute or leaf element type set,
          // use the reference descriptor -  make sure it is non-abstract
          if (Modifier.isAbstract(aDescriptor.getJavaClass().getModifiers())) {
            // throw an exception
            throw DescriptorException.missingClassIndicatorField(
                nestedRow, aDescriptor.getInheritancePolicy().getDescriptor());
          }
        }
      }

      // Object element
      objectToAdd =
          buildCompositeObject(
              aDescriptor, nestedRow, sourceQuery, null, joinManager, executionSession);
      objectToAdd =
          convertDataValueToObjectValue(
              objectToAdd, executionSession, ((XMLRecord) nestedRow).getUnmarshaller());
    }
    return objectToAdd;
  }
  /**
   * INTERNAL: Build and return the nested rows from the specified field value. This method allows
   * the field value to be an ARRAY containing other structures such as arrays or Struct, or direct
   * values.
   */
  public static Object buildContainerFromArray(
      Array fieldValue, ObjectRelationalDatabaseField arrayField, AbstractSession session)
      throws DatabaseException {
    if (arrayField.getType() == null) {
      return fieldValue;
    }
    Object[] objects = null;
    try {
      objects = (Object[]) fieldValue.getArray();
    } catch (java.sql.SQLException ex) {
      throw DatabaseException.sqlException(ex, session, false);
    }
    if (objects == null) {
      return null;
    }

    boolean isNestedStructure = false;
    ObjectRelationalDataTypeDescriptor ord = null;
    DatabaseField nestedType = null;
    if (arrayField != null) {
      nestedType = arrayField.getNestedTypeField();
      if ((nestedType != null) && nestedType.getSqlType() == Types.STRUCT) {
        ClassDescriptor descriptor = session.getDescriptor(nestedType.getType());
        if ((descriptor != null) && (descriptor.isObjectRelationalDataTypeDescriptor())) {
          // this is used to convert non-null objects passed through stored procedures and custom
          // SQL to structs
          ord = (ObjectRelationalDataTypeDescriptor) descriptor;
        }
      } else if ((nestedType != null) && (nestedType instanceof ObjectRelationalDatabaseField)) {
        isNestedStructure = true;
      }
    }
    // handle ARRAY conversions
    ReadObjectQuery query = new ReadObjectQuery();
    query.setSession(session);
    ContainerPolicy cp = ContainerPolicy.buildPolicyFor(arrayField.getType());
    Object container = cp.containerInstance(objects.length);
    for (int i = 0; i < objects.length; i++) {
      Object arrayValue = objects[i];
      if (arrayValue == null) {
        return null;
      }
      if (ord != null) {
        AbstractRecord nestedRow = ord.buildRowFromStructure((Struct) arrayValue);
        ClassDescriptor descriptor = ord;
        if (descriptor.hasInheritance()) {
          Class newElementClass =
              descriptor.getInheritancePolicy().classFromRow(nestedRow, session);
          if (!descriptor.getJavaClass().equals(newElementClass)) {
            descriptor = session.getDescriptor(newElementClass);
            if (descriptor == null) {
              descriptor = ord;
            }
          }
        }
        arrayValue = descriptor.getObjectBuilder().buildNewInstance();
        descriptor
            .getObjectBuilder()
            .buildAttributesIntoObject(arrayValue, nestedRow, query, null, false);
      } else if (isNestedStructure && (arrayValue instanceof Array)) {
        arrayValue =
            buildContainerFromArray(
                (Array) arrayValue, (ObjectRelationalDatabaseField) nestedType, session);
      }

      cp.addInto(arrayValue, container, session);
    }
    return container;
  }