My apologies for the delay. I did not receive any email notifications that a response had been made. I've rectified that for the future.
I am using CollQuery because I am trying to perform a query against a collection of objects already in memory. To my previous mention of SQL, I can build up a SQL query to retrieve the data if I mock it up in a database, but I now think that I had used subqueries when doing that.
I am currently on a project that is using Oracle Label Security to protect their data in the database and they want to use a separate metadata tagging system to generate the OLS caveats. I am trying to build a translation system between the OLS caveats and the metadata tags. One looper here is that the metadata management is handled by a separate web service that I must call to get the pre-defined metadata combinations. For performance reasons, I do not want to call that service for every persisted record. Instead I create a Collection of the metadata objects to hold in cache and refresh regularly.
I do not have access to the Q classes on the other side of the service so I am also using alias and $() helpers.
So here are my classes:
class SecurityMetaData {
private Long id;
private ClassificationTag classification;
// This collection holds all tags that are required (all) when using this metadata object.
private Set<LabelTagsRequired> requiredTags;
// This collection holds all tags that are optional (any, but user must have at least one) when using this metadata object.
private Set<LabelTagsOptional> optionalTags;
public String toString(){
// Over simplified - there is parsing and formatting that happens to make this pretty.
return classification.toString()+requiredTags.toString()+optionalTags.toString();
}
}
class LabelTagsRequired extends LabelTag {
}
class LabelTagsOptional extends LabelTag {
}
class ClassificationTag extends LabelTag {
}
abstract class LabelTag {
protected Long id;
protected String publicName;
protected String publicDescription;
protected String olsName;
}
So the issue I am having is when I want to query for a specific SecurityMetadata object.
Sample data where tags are delimited by "/" and the fields are delimited by "|" :
sensitive|accounting/finance|proposals/businessdev
private|accounting/operations|activeCustomer/customerHistory
public|accounting/finance
public|finance/operations
sensitive|accounting/finance
sensitive|finance
sensitive|proposals
The tags are not guaranteed to ever come to me in a consistent order and some strings do not contain required tags while others contain a required tag and not an optional tag.
Here is what I am working with:
// The following values are pre-parsed and collected:
String classificationTag;
List<String> requiredTags;
List<String> optionalTags;
BooleanBuilder builder = new BooleanBuilder();
SecurityMetadata metadataAlias =
alias(SecurityMetadata.class, "securityMetadata");
LabelTagsRequired requiredAlias =
alias(LabelTagsRequired.class, "labelTagsRequired");
LabelTagsOptional optionalAlias = alias(LabelTagsOptional.class, "labelTagsOptional");
boolean optionalFilterAdded = false;
CollQuery query =
new CollQuery().from($(metadataAlias), securityMetadataCache);
query.leftJoin($(metadataAlias.getRequiredTags()), $(requiredAlias));
query.leftJoin($(metadataAlias.getOptionalTags()), $(optionalAlias));
builder.and($(metadataAlias.getClassificationTag().getPublicName()).eq(
classificationTag));
if (requiredTags != null && requiredTags.size() > 0)
{
BooleanBuilder requiredBuilder = new BooleanBuilder();
if (optionalTags == null || optionalTags.isEmpty())
{
requiredBuilder.and($(requiredAlias.getPublicName())
.in(requiredTags)
.and(
$(requiredAlias.getPublicName())
.notIn(requiredTags).not())
.and($(metadataAlias.getOptionalTags()).isEmpty()));
requiredBuilder.or(($(optionalAlias.getPublicName())
.in(requiredTags)).and(
($(optionalAlias.getPublicName()).notIn(requiredTags)).not())
.and($(metadataAlias.getRequiredTags().isEmpty())));
optionalFilterAdded = true;
}
else
{
requiredBuilder.and($(requiredAlias.getPublicName()).in(
requiredTags).and(
$(requiredAlias.getPublicName()).notIn(requiredTags)
.not()));
}
builder.and((requiredBuilder));
}
else
{
builder.and($(metadataAlias.getRequiredTags().isEmpty()));
}
if (!optionalFilterAdded)
{
BooleanBuilder optionalBuilder = new BooleanBuilder();
if (optionalTags != null && optionalTags.size() > 0)
{
optionalBuilder.and(($(optionalAlias.getPublicName()).in(optionalTags))
.and($(optionalAlias.getPublicName()).notIn(optionalTags).not()));
}
else
{
optionalBuilder.and($(metadataAlias.getOptionalTags().isEmpty()));
}
builder.and(optionalBuilder);
}
query.where(builder);
for (SecurityMetadata data : query.list($(metadataAlias)))
{
returnVal = data;
}
Here is the resulting builder.getValue() when searching for sensitive|finance. The results come back with multiple records; all of the sensitive records that contain "finance" in the required tags.
securityMetadata.classificationTag.publicName = sensitive && labelTagsRequired.publicName = finance && !labelTagsRequired.publicName != finance && empty(securityMetadata.optionalTags) || labelTagsOptional.publicName = finance && !labelTagsOptional.publicName != finance && securityMetadata.requiredTags.empty
Here is the resulting builder.getValue() when searching for sensitive|proposals. There are no results found despite my being able to review the collection and know that it does exist in there.
securityMetadata.classificationTag.publicName = sensitive && labelTagsRequired.publicName = proposals && !labelTagsRequired.publicName != proposals && empty(securityMetadata.optionalTags) || labelTagsOptional.publicName = proposals && !labelTagsOptional.publicName != proposals && securityMetadata.requiredTags.empty
I can interrogate the builder object and see that there are several levels of arguments and that they appear to break apart at the right places. But I am not able to verify the boxing.
Any thoughts?