package com.openbase.webobjects.qualifiers;
//
// InSubqueryQualifier.java
//
// Much thanks to the Wonder guys and Pierre Bernard for their helpful examples
//
// Created by Alex Cone on 12/18/05.
// Copyright (c) 2005 __MyCompanyName__. All rights reserved.
//
import java.lang.reflect.Constructor;
import java.util.Enumeration;
import java.util.StringTokenizer;
import com.webobjects.eoaccess.EOAdaptor;
import com.webobjects.eoaccess.EOAttribute;
import com.webobjects.eoaccess.EODatabaseContext;
import com.webobjects.eoaccess.EOEntity;
import com.webobjects.eoaccess.EOQualifierSQLGeneration;
import com.webobjects.eoaccess.EORelationship;
import com.webobjects.eoaccess.EOSQLExpression;
import com.webobjects.eoaccess.EOSQLExpressionFactory;
import com.webobjects.eocontrol.EOClassDescription;
import com.webobjects.eocontrol.EOFetchSpecification;
import com.webobjects.eocontrol.EOObjectStoreCoordinator;
import com.webobjects.eocontrol.EOQualifier;
import com.webobjects.eocontrol.EOQualifierEvaluation;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSForwardException;
import com.webobjects.foundation.NSKeyValueCodingAdditions;
import com.webobjects.foundation.NSMutableSet;
public class InSubqueryQualifier extends EOQualifier implements EOQualifierEvaluation, Cloneable {
private static final String InKeyword = " IN ";
/** Path to an attribute or relationship of the qualified entity
*/
protected String _key;
/** Name of the entity from which to get values to match against
*/
protected String _entityName;
/** Name of the attribute in the destination entity to match against
*/
protected String _attributePath;
/** Qualifier to limit the list of acceptable values
*/
protected EOQualifier _subQualifier;
/** register SQL generation support for the qualifier */
static {
EOQualifierSQLGeneration.Support.setSupportForClass(new InSubqueryQualifierSQLGenerationSupport(), InSubqueryQualifier.class);
}
/** Constructor for queries off an attribute.
*
* @param key key path to an attribute of the qualified entity
* @param entityName name of the entity from which to get values to match against
* @param attributePath name of the attribute in the destination entity to match against
* @param subQualifier qualifier to limit the list of acceptable values
*/
public InSubqueryQualifier(String key, String entityName, String attributePath, EOQualifier subQualifier) {
if ((key == null) || (entityName == null) || (attributePath == null)) {
throw new IllegalArgumentException("Arguments key, entityName and attributePath may not be null");
}
this.setKey(key);
this.setEntityName(entityName);
this.setAttributePath(attributePath);
this.setSubQualifier(subQualifier);
}
/** Constructor for queries off a relationship
*
* @param key key path to a relationship of the qualified entity
* @param subQualifier qualifier to limit the list of acceptable values
*/
public InSubqueryQualifier(String key, EOQualifier subQualifier) {
if (key == null) {
throw new IllegalArgumentException("Argument key may not be null");
}
this.setKey(key);
this.setSubQualifier(subQualifier);
}
public String key() {
return _key;
}
public void setKey(String aValue) {
_key = aValue;
}
public String entityName() {
return _entityName;
}
public void setEntityName(String aValue) {
_entityName = aValue;
}
public String attributePath() {
return _attributePath;
}
public void setAttributePath(String aValue) {
_attributePath = aValue;
}
public EOQualifier subQualifier() {
return _subQualifier;
}
public void setSubQualifier(EOQualifier aValue) {
_subQualifier = aValue;
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("(");
buffer.append(key());
buffer.append(InKeyword);
buffer.append("(");
buffer.append(" SELECT ");
buffer.append((attributePath() != null) ? attributePath() : "*");
if (entityName() != null) {
buffer.append(" FROM ");
buffer.append(entityName());
}
if (subQualifier() != null) {
buffer.append(" WHERE ");
buffer.append(subQualifier().toString());
}
buffer.append(")");
return buffer.toString();
}
public void addQualifierKeysToSet(NSMutableSet keySet) {
keySet.addObject(key());
if (subQualifier() != null) {
NSMutableSet subKeySet = new NSMutableSet();
subQualifier().addQualifierKeysToSet(subKeySet);
if (entityName() == null) {
Enumeration subKeys = subKeySet.objectEnumerator();
String prefix = key() + NSKeyValueCodingAdditions.KeyPathSeparator;
while (subKeys.hasMoreElements()) {
keySet.addObject(prefix + subKeys.nextElement());
}
} else {
keySet.addObjectsFromArray(subKeySet.allObjects());
}
}
}
// we don't do bindings yet
public EOQualifier qualifierWithBindings(NSDictionary someBindings, boolean requiresAll) {
return (EOQualifier) this.clone();
}
// we don't do validation
public void validateKeysWithRootClassDescription(EOClassDescription aClassDescription) {
}
public Object clone() {
return new InSubqueryQualifier(key(), entityName(), attributePath(), subQualifier());
}
public static class InSubqueryQualifierSQLGenerationSupport extends EOQualifierSQLGeneration.Support {
public InSubqueryQualifierSQLGenerationSupport() {
super();
}
public String sqlStringForSQLExpression(EOQualifier eoqualifier, EOSQLExpression aSQLExpression) {
String sqlString = null;
if ((aSQLExpression != null) && (aSQLExpression.entity() != null)) {
InSubqueryQualifier isQualifier = (InSubqueryQualifier)eoqualifier;
EOEntity anEntity = aSQLExpression.entity();
String aKey = isQualifier.key();
StringBuffer sb = new StringBuffer();
String attributeString = aSQLExpression.sqlStringForAttributeNamed(aKey);
sb.append(aSQLExpression.formatSQLString(attributeString, attributeForPath(anEntity, aKey).readFormat()));
sb.append(InSubqueryQualifier.InKeyword);
sb.append("(");
EOEntity subEntity = anEntity.model().modelGroup().entityNamed(isQualifier.entityName());
EODatabaseContext context = EODatabaseContext.registeredDatabaseContextForModel(subEntity.model(),
EOObjectStoreCoordinator.defaultCoordinator());
EOSQLExpressionFactory factory = context.database().adaptor().expressionFactory();
EOSQLExpression subExpression = factory.expressionForEntity(subEntity);
// EOSQLExpression subExpression = expressionForEntity(subEntity);
EOFetchSpecification subFetch = new EOFetchSpecification(subEntity.name(), isQualifier.subQualifier(), null);
String attributePath = isQualifier.attributePath();
NSArray subAttributes;
if (attributePath != null) {
subAttributes = new NSArray(attributeForPath(subEntity, attributePath));
} else {
subAttributes = subEntity.primaryKeyAttributes();
}
StringBuffer subBuffer = new StringBuffer();
subExpression.aliasesByRelationshipPath().setObjectForKey("t1", "");
subExpression.setUseAliases(true);
subExpression.prepareSelectExpressionWithAttributes(subAttributes, false, subFetch);
subBuffer.append("SELECT ");
subBuffer.append(subExpression.listString());
subBuffer.append(" FROM ");
subBuffer.append(subExpression.tableListWithRootEntity(subEntity));
boolean hasWhereClause = ((subExpression.whereClauseString() != null) &&
(subExpression.whereClauseString().length() > 0));
if (hasWhereClause) {
subBuffer.append(" WHERE ");
subBuffer.append(subExpression.whereClauseString());
}
if ((subExpression.joinClauseString() != null)
&& (subExpression.joinClauseString().length() > 0)) {
if (hasWhereClause) {
subBuffer.append(" AND ");
}
subBuffer.append(subExpression.joinClauseString());
}
String subquerySqlString = subBuffer.toString();
sb.append(subquerySqlString.replaceAll("t0.", "t1."));
sb.append(")");
sqlString = sb.toString();
Enumeration bindVariables = subExpression.bindVariableDictionaries().objectEnumerator();
while (bindVariables.hasMoreElements()) {
aSQLExpression.addBindVariableDictionary((NSDictionary) bindVariables.nextElement());
}
}
return sqlString;
}
public EOQualifier schemaBasedQualifierWithRootEntity(EOQualifier qualifier, EOEntity entity) {
return qualifier;
}
public EOQualifier qualifierMigratedFromEntityRelationshipPath(EOQualifier eoqualifier, EOEntity eoentity, String s) {
// the key migration is the same as for EOKeyValueQualifier
InSubqueryQualifier isQualifier=(InSubqueryQualifier)eoqualifier;
return new InSubqueryQualifier(_translateKeyAcrossRelationshipPath(isQualifier.key(), s, eoentity),
isQualifier.entityName(), isQualifier.attributePath(), isQualifier.subQualifier() );
}
// Protected instance methods
protected EOAttribute attributeForPath(EOEntity entity, String keyPath) {
if (keyPath != null) {
StringTokenizer tokenizer = new StringTokenizer(keyPath, NSKeyValueCodingAdditions.KeyPathSeparator);
EORelationship relationship = null;
while (tokenizer.hasMoreElements()) {
String key = tokenizer.nextToken();
if (tokenizer.hasMoreElements()) {
relationship = entity.anyRelationshipNamed(key);
} else {
return entity.anyAttributeNamed(key);
}
if (relationship != null) {
entity = relationship.destinationEntity();
} else {
return null;
}
}
return null;
}
return null;
}
protected EOSQLExpression expressionForEntity(EOEntity entity) {
try {
Class expressionClass = ((EOAdaptor)EOAdaptor.adaptorWithModel(entity.model())).expressionClass();
Constructor constructor = expressionClass.getConstructor(new Class[] { EOEntity.class });
EOSQLExpression expression = (EOSQLExpression)constructor.newInstance(new Object[] { entity });
return expression;
} catch (Exception exception) {
throw new NSForwardException(exception);
}
}
}
}