private int determineLevelsRemovedFromStandardDatatype(List<CqlDataBucket> typesProcessingList) { int count = 0; for (int i = typesProcessingList.size() - 1; i >= 0; i--) { count++; if (DatatypeFlavor.STANDARD.equals(typesProcessingList.get(i).datatypeFlavor)) { break; } } return count; }
/** * Processes CQL associations into HQL * * @param association The CQL association * @param hql The HQL fragment which will be edited * @param parameters The positional HQL query parameters * @param associationTrace The trace of associations * @param sourceClassName The class name of the type to which this association belongs * @throws QueryTranslationException */ private void processAssociation( CQLAssociatedObject association, StringBuilder hql, List<java.lang.Object> parameters, Stack<CQLAssociatedObject> associationStack, List<CqlDataBucket> typesProcessingList, CQLObject sourceQueryObject, String sourceAlias) throws QueryTranslationException { LOG.debug( "Processing association " + sourceQueryObject.getClassName() + " to " + association.getClassName()); // get the association's role name String roleName = association.getEndName(); if (roleName == null) { try { roleName = typesInformationResolver.getRoleName( sourceQueryObject.getClassName(), association.getClassName()); } catch (TypesInformationException ex) { throw new QueryTranslationException(ex.getMessage(), ex); } } if (roleName == null) { // still null?? no association to the object! throw new QueryTranslationException( "No role name for an association between " + sourceQueryObject.getClassName() + " and " + association.getClassName() + " cound be determined. Maybe the association doesn't exist?"); } LOG.debug("Role name determined to be " + roleName); // determine the alias for this association String alias = getAssociationAlias(sourceQueryObject.getClassName(), association.getClassName(), roleName); LOG.debug("Association alias determined to be " + alias); // add this association to the stack associationStack.push(association); DatatypeFlavor flavor = null; try { flavor = DatatypeFlavor.getFlavorOfClass(Class.forName(stripGeneric(association.getClassName()))); } catch (ClassNotFoundException ex) { throw new QueryTranslationException( "Error determining datatype flavor of " + association.getClassName() + ": " + ex.getMessage(), ex); } addTypeProcessingInformation( typesProcessingList, association.getClassName(), flavor == DatatypeFlavor.STANDARD ? alias : roleName); if (DatatypeFlavor.STANDARD.equals(flavor)) { // flag indicates the query is only verifying the association is populated boolean simpleNullCheck = true; if (association.getCQLAttribute() != null) { simpleNullCheck = false; hql.append(sourceAlias).append('.').append(roleName); hql.append(".id in (select ").append(alias).append(".id from "); hql.append(association.getClassName()).append(" as ").append(alias).append(" where "); processAttribute( association.getCQLAttribute(), hql, parameters, association, alias, associationStack, typesProcessingList); hql.append(") "); } if (association.getCQLAssociatedObject() != null) { simpleNullCheck = false; // add clause to select things from this association hql.append(sourceAlias).append('.').append(roleName); hql.append(".id in (select ").append(alias).append(".id from "); hql.append(association.getClassName()).append(" as ").append(alias).append(" where "); processAssociation( association.getCQLAssociatedObject(), hql, parameters, associationStack, typesProcessingList, association, alias); hql.append(") "); } if (association.getCQLGroup() != null) { simpleNullCheck = false; hql.append(sourceAlias).append('.').append(roleName); hql.append(".id in (select ").append(alias).append(".id from "); hql.append(association.getClassName()).append(" as ").append(alias).append(" where "); processGroup( association.getCQLGroup(), hql, parameters, associationStack, typesProcessingList, association, alias); hql.append(") "); } if (simpleNullCheck) { // query is checking for the association to exist and be non-null hql.append(sourceAlias).append('.').append(roleName).append(".id is not null "); } } else { // complex datatype association (modeled as an attribute, so saying "Person.AD is not null" // doesn't make sense... // "Person.AD.NullFlavor = NullFlavor.NI, however, is fine // FIXME: have to handle complex types here boolean simpleNullCheck = true; if (association.getCQLAssociatedObject() != null) { simpleNullCheck = false; // continue processing // TODO: does alias need to be role name? processAssociation( association.getCQLAssociatedObject(), hql, parameters, associationStack, typesProcessingList, association, alias); } if (association.getCQLGroup() != null) { simpleNullCheck = false; // continue processing // TODO: does alias need to be role name? processGroup( association.getCQLGroup(), hql, parameters, associationStack, typesProcessingList, association, alias); } if (association.getCQLAttribute() != null) { simpleNullCheck = false; // TODO: does sourceAlias need to be roleName?? processAttribute( association.getCQLAttribute(), hql, parameters, sourceQueryObject, sourceAlias, associationStack, typesProcessingList); } if (simpleNullCheck) { // checking for the type not to be null, but .id doesn't work.... // depending on the sequence of datatype flavors leading to this point // we have to construct the HQL in different ways String path = getAssociationNavigationPath(typesProcessingList, 4); if (path.startsWith("join ")) { // throw away the "where" part of the existing query if (hql.toString().endsWith("where ")) { removeLastWhereStatement(hql); } } hql.append(path).append(" is not null"); } } // pop this association off the stack associationStack.pop(); clipTypeProcessingInformation(typesProcessingList); LOG.debug(associationStack.size() + " associations remain on the stack"); }