@Override public ClassDescriptor getDescriptor() { if (isAttribute()) { return null; } if (descriptor == null) { // Look first for query keys, then mappings. Ultimately we should have query keys // for everything and can dispense with the mapping part. ForeignReferenceQueryKey queryKey = (ForeignReferenceQueryKey) getQueryKeyOrNull(); if (queryKey != null) { descriptor = convertToCastDescriptor( getSession().getDescriptor(queryKey.getReferenceClass()), getSession()); return descriptor; } if (getMapping() == null) { throw QueryException.invalidQueryKeyInExpression(this); } // We assume this is either a foreign reference or an aggregate mapping descriptor = getMapping().getReferenceDescriptor(); if (getMapping().isVariableOneToOneMapping()) { throw QueryException.cannotQueryAcrossAVariableOneToOneMapping(getMapping(), descriptor); } descriptor = convertToCastDescriptor(descriptor, getSession()); } return descriptor; }
/** * 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 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()); }
public DatabaseMapping getMappingFromQueryKey() { QueryKey queryKey = getQueryKeyOrNull(); if ((queryKey == null) || (!(queryKey instanceof DirectQueryKey))) { throw QueryException.cannotConformExpression(); } mapping = queryKey .getDescriptor() .getObjectBuilder() .getMappingForField(((DirectQueryKey) queryKey).getField()); if (mapping == null) { throw QueryException.cannotConformExpression(); } return mapping; }
/** 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(); }
/** * PUBLIC: Configure the query to use an instance of the specified container class to hold the * result objects. The key used to index the value in the Map is the value returned by a call to * the specified zero-argument method. The method must be implemented by the class (or a * superclass) of the value to be inserted into the Map. * * <p>jdk1.2.x: The container class must implement (directly or indirectly) the Map interface. * * <p>jdk1.1.x: The container class must be a subclass of Hashtable. * * <p>The referenceClass must set before calling this method. */ public void useMapClass(Class concreteClass, String methodName) { // the reference class has to be specified before coming here if (getReferenceClass() == null) { throw QueryException.referenceClassMissing(this); } ContainerPolicy policy = ContainerPolicy.buildPolicyFor(concreteClass); policy.setKeyName(methodName, getReferenceClass().getName()); setContainerPolicy(policy); }
/** 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: Execute the query. If there are cached results return those. This must override the * super to support result caching. * * @param session - the session in which the receiver will be executed. * @return An object or vector, the result of executing the query. * @exception DatabaseException - an error has occurred on the database */ public Object execute(AbstractSession session, AbstractRecord row) throws DatabaseException { if (shouldCacheQueryResults()) { if (getContainerPolicy().overridesRead()) { throw QueryException.cannotCacheCursorResultsOnQuery(this); } if (shouldConformResultsInUnitOfWork()) { throw QueryException.cannotConformAndCacheQueryResults(this); } if (isPrepared()) { // only prepared queries can have cached results. Object queryResults = getQueryResults(session, row, true); if (queryResults != null) { if (QueryMonitor.shouldMonitor()) { QueryMonitor.incrementReadAllHits(this); } // bug6138532 - check for "cached no results" (InvalidObject singleton) in query // results, and return an empty container instance as configured if (queryResults == InvalidObject.instance) { return getContainerPolicy().containerInstance(0); } Collection results = (Collection) queryResults; if (session.isUnitOfWork()) { ContainerPolicy policy = getContainerPolicy(); Object resultCollection = policy.containerInstance(results.size()); Object iterator = policy.iteratorFor(results); while (policy.hasNext(iterator)) { Object result = ((UnitOfWorkImpl) session) .registerExistingObject(policy.next(iterator, session), this.descriptor); policy.addInto(result, resultCollection, session); } return resultCollection; } return results; } } } if (QueryMonitor.shouldMonitor()) { QueryMonitor.incrementReadAllMisses(this); } return super.execute(session, row); }
public QueryKey getQueryKeyOrNull() { if (!hasQueryKey) { return null; } // Oct 19, 2000 JED // Added try/catch. This was throwing a NPE in the following case // expresssionBuilder.get("firstName").get("bob") // moved by Gordon Yorke to cover validate and normalize if (getContainingDescriptor() == null) { throw QueryException.invalidQueryKeyInExpression(getName()); } if (queryKey == null) { queryKey = getContainingDescriptor().getQueryKeyNamed(getName()); if (queryKey == null) { hasQueryKey = false; } } return queryKey; }
/** * 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: Specify the foreign-reference mapped attribute to be optimized in this query. The query * will execute normally, however when any of the batched parts is accessed, the parts will all be * read in a single query, this allows all of the data required for the parts to be read in a * single query instead of (n) queries. This should be used when the application knows that it * requires the part for all of the objects being read. This can be used for one-to-one, * one-to-many, many-to-many and direct collection mappings. * * <p>The use of the expression allows for nested batch reading to be expressed. * * <p>Example: query.addBatchReadAttribute("phoneNumbers") * * @see #addBatchReadAttribute(Expression) * @see ObjectLevelReadQuery#addJoinedAttribute(String) */ public void addBatchReadAttribute(String attributeName) { if (!getQueryMechanism().isExpressionQueryMechanism()) { throw QueryException.batchReadingNotSupported(this); } getBatchReadAttributeExpressions().add(getExpressionBuilder().get(attributeName)); }
/** * INTERNAL: Possible for future development, not currently supported. * * <p>Retrieve the value through using batch reading. This executes a single query to read the * target for all of the objects and stores the result of the batch query in the original query to * allow the other objects to share the results. */ @Override protected Object batchedValueFromRow(AbstractRecord row, ReadAllQuery query) { throw QueryException.batchReadingNotSupported(this, query); }