private boolean isAssociationToIsoType(ClassAssociation ca) throws QueryTranslationException { Class<?> clazz = null; try { clazz = Class.forName(ca.getClassName()); } catch (ClassNotFoundException ex) { throw new QueryTranslationException("Error loading class " + ca.getClassName()); } DatatypeFlavor flavor = DatatypeFlavor.getFlavorOfClass(clazz); return !flavor.equals(DatatypeFlavor.STANDARD); }
/** * Processes a CQL query attribute into HQL * * @param attribute The CQL attribute * @param hql The HQL statement fragment * @param parameters The positional parameters list * @param associationTrace The trace of associations * @param objectClassName The class name of the object to which this association belongs * @throws QueryTranslationException */ private void processAttribute( CQLAttribute attribute, StringBuilder hql, List<java.lang.Object> parameters, CQLObject queryObject, String queryObjectAlias, Stack<CQLAssociatedObject> associationStack, List<CqlDataBucket> typesProcessingList) throws QueryTranslationException { LOG.debug("Processing attribute " + queryObject.getClassName() + "." + attribute.getName()); // determine what the flavor of this attribute is DatatypeFlavor flavor = typesProcessingList.get(typesProcessingList.size() - 1).datatypeFlavor; LOG.debug("Datatype flavor is " + flavor.name()); // DSET<Ii>, (and TEL and CD) ends up as "COMPLEX_WITH_SIMPLE_CONTENT" because it's modeled as // an // association to DSET, then to Ii, which is that type. Appears to work OK. // FIXME: DSET<Ad> doesn't work because I can't get the information about the part names inside // the AD // out of the Hibernate configuration object API. Interestingly, AD by itself is fine. switch (flavor) { case STANDARD: case ENUMERATION: processStandardAttribute(attribute, hql, parameters, queryObject, queryObjectAlias); break; case COMPLEX_WITH_SIMPLE_CONTENT: processComplexAttributeWithSimpleOrMixedContent( attribute, hql, parameters, associationStack, typesProcessingList); break; case COMPLEX_WITH_MIXED_CONTENT: processComplexAttributeWithSimpleOrMixedContent( attribute, hql, parameters, associationStack, typesProcessingList); break; case COMPLEX_WITH_COLLECTION_OF_COMPLEX: if (currentlyWrappedByDset(typesProcessingList)) { processDsetOfComplexDatatypeWithCollectionOfComplexAttributesWithSimpleContent( attribute, hql, parameters, associationStack, typesProcessingList); } else { processComplexAttributeWithCollectionOfComplexAttributesWithSimpleContent( attribute, hql, parameters, associationStack, typesProcessingList); } break; case COLLECTION_OF_COMPLEX_WITH_SIMPLE_CONTENT: processComplexAttributeWithSimpleOrMixedContent( attribute, hql, parameters, associationStack, typesProcessingList); break; case COLLECTION_OF_COMPLEX_WITH_COLLECTION_OF_COMPLEX_WITH_SIMPLE_CONTENT: // gah break; } }
private Object getAttributeValueObject(Class<?> fieldType, AttributeValue value) throws QueryTranslationException { Object actualValue = null; // handle a couple special cases if (DatatypeFlavor.getFlavorOfClass(fieldType) == DatatypeFlavor.ENUMERATION) { // 1) ISO 21090enumerations (NullFlavor, AddressPartType, etc) String enumValue = value.getStringValue(); LOG.debug("Field type is an Enumeration"); try { Method factoryMethod = fieldType.getMethod("valueOf", String.class); actualValue = factoryMethod.invoke(null, enumValue); } catch (Exception ex) { throw new QueryTranslationException( "Error converting " + enumValue + " to its enumeration value: " + ex.getMessage(), ex); } } else if (Character.class.equals(fieldType)) { // 2) Character String stringVal = value.getStringValue(); if (stringVal.length() == 1) { actualValue = Character.valueOf(stringVal.charAt(0)); } else { throw new QueryTranslationException( "The string value \"" + value + "\" of length " + stringVal.length() + " is not a valid character (should be length 1)"); } } else if (URI.class.equals(fieldType)) { // 3) URI actualValue = URI.create(value.getStringValue()); } else { if (value.getStringValue() != null) { actualValue = value.getStringValue(); } else if (value.getBooleanValue() != null) { actualValue = value.getBooleanValue(); } else if (value.getDateValue() != null) { actualValue = value.getDateValue(); } else if (value.getDoubleValue() != null) { actualValue = value.getDoubleValue(); } else if (value.getIntegerValue() != null) { actualValue = value.getIntegerValue(); } else if (value.getLongValue() != null) { actualValue = value.getLongValue(); } else if (value.getTimeValue() != null) { actualValue = value.getTimeValue().toString(); } } return actualValue; }
private void addTypeProcessingInformation( List<CqlDataBucket> typesProcessingList, String className, String aliasOrRoleName) throws QueryTranslationException { DatatypeFlavor flavor = null; try { flavor = DatatypeFlavor.getFlavorOfClass(Class.forName(stripGeneric(className))); } catch (Exception ex) { throw new QueryTranslationException( "Error determining datatype flavor of " + className + ": " + ex.getMessage(), ex); } CqlDataBucket bucket = new CqlDataBucket(); bucket.clazz = className; bucket.aliasOrRoleName = aliasOrRoleName; bucket.datatypeFlavor = flavor; typesProcessingList.add(bucket); }
/** * 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"); }