package com.idega.block.dataquery.data.sql;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.idega.block.dataquery.data.QueryConstants;
import com.idega.block.dataquery.data.xml.QueryEntityPart;
import com.idega.data.EntityControl;
import com.idega.data.GenericEntity;
import com.idega.data.IDOCompositePrimaryKeyException;
import com.idega.data.IDOEntity;
import com.idega.data.IDOEntityDefinition;
import com.idega.data.IDOEntityField;
import com.idega.data.IDORelationshipException;
import com.idega.repository.data.RefactorClassRegistry;
/**
* <p>Title: idegaWeb</p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: idega Software</p>
* @author <a href="thomas@idega.is">Thomas Hilbig</a>
* @version 1.0
* Created on Oct 8, 2003
*/
public class PathCriterionExpression implements DynamicExpression {
protected QueryEntityPart queryEntityPart = null;
protected SQLQuery sqlQuery = null;
private List criteriaList = null;
private List innerJoins = new ArrayList();
public PathCriterionExpression(QueryEntityPart queryEntityPart, SQLQuery sqlQuery) {
this.queryEntityPart = queryEntityPart;
this.sqlQuery = sqlQuery;
try {
initialize();
}
catch (ExpressionException ex) {
this.criteriaList = null;
}
catch (IDOCompositePrimaryKeyException e) {
this.criteriaList = null;
}
}
protected void initialize() throws IDOCompositePrimaryKeyException, ExpressionException {
List pathElements = this.queryEntityPart.getPathNames();
// Note: targetPath is either a class name or a query name
String targetPath= (String) pathElements.get(0);
String tableName = this.sqlQuery.getTableName(targetPath, targetPath);
this.innerJoins.add(new InnerJoinExpression(tableName, targetPath, this.sqlQuery));
if (pathElements.size() > 1) {
// at the moment path elements have only more than one element if the first element is not a query but an EJB
// that why we can try to get an instance
this.criteriaList = new ArrayList();
// start with the first element
IDOEntity entity = getInstance(targetPath);
IDOEntityDefinition definition = entity.getEntityDefinition();
getConditions(definition, targetPath, pathElements, 1, this.criteriaList);
}
}
private void getConditions(IDOEntityDefinition sourceDefinition, String targetPath, List pathElements, int listIndex, List criteria)
throws ExpressionException, IDOCompositePrimaryKeyException {
String pathElement = (String) pathElements.get(listIndex);
String sourcePath = targetPath;
// new target
targetPath = new StringBuffer(targetPath).append(QueryConstants.ENTITY_PATH_DELIMITER).append(pathElement).toString();
IDOEntityDefinition targetDefinition =
lookForTargetEntityAmongManyToManyRelations(sourceDefinition, pathElement);
if (targetDefinition == null) {
// many to one relation
targetDefinition = lookForTargetEntityAmongManyToOneRelations(sourceDefinition, pathElement);
if (targetDefinition == null) {
String message = "[" + this.getClass().getName() + "] Path element could not be resolved.";
throw new ExpressionException(message);
}
getConditionManyToOneRelation(sourceDefinition, sourcePath , targetDefinition, targetPath, pathElement, criteria);
}
else {
getConditionManyToManyRelation(sourceDefinition, sourcePath, targetDefinition, targetPath, criteria);
}
if (pathElements.size() > ++listIndex) {
getConditions(targetDefinition, targetPath, pathElements, listIndex, criteria);
}
}
protected void getConditionManyToManyRelation(IDOEntityDefinition sourceDefinition, String sourcePath, IDOEntityDefinition targetDefinition, String targetPath, List criteria) throws IDOCompositePrimaryKeyException {
// many to many relation
String sourcePrimaryKeyColumnName = sourceDefinition.getPrimaryKeyDefinition().getField().getSQLFieldName();
String targetPrimaryKeyColumnName = targetDefinition.getPrimaryKeyDefinition().getField().getSQLFieldName();
String sourceTableName = sourceDefinition.getSQLTableName();
String targetTableName = targetDefinition.getSQLTableName();
// get aliases
String aliasSourceTableName = this.sqlQuery.getUniqueNameForEntityByTableName(sourceTableName, sourcePath);
String aliasTargetTableName = this.sqlQuery.getUniqueNameForEntityByTableName(targetTableName, targetPath);
// retrieve name of middle table
Class sourceClass = sourceDefinition.getInterfaceClass();
Class targetClass = targetDefinition.getInterfaceClass();
String middleTable = EntityControl.getManyToManyRelationShipTableName(sourceClass, targetClass);
//String middleTable = StringHandler.concatAlphabetically(sourceTableName, targetTableName, "_");
// just a decision: middle table gets the source path
String aliasMiddleTable = this.sqlQuery.getUniqueNameForEntityByTableName(middleTable, sourcePath);
// build the condition
StringBuffer buffer = new StringBuffer(" (");
buffer.append(aliasSourceTableName);
buffer.append('.').append(sourcePrimaryKeyColumnName);
buffer.append("=");
buffer.append(aliasMiddleTable);
buffer.append('.').append(sourcePrimaryKeyColumnName);
buffer.append(" AND ");
buffer.append(aliasMiddleTable);
buffer.append('.').append(targetPrimaryKeyColumnName);
buffer.append("=");
buffer.append(aliasTargetTableName);
buffer.append('.').append(targetPrimaryKeyColumnName);
buffer.append(") ");
// add the middle table to the query
this.innerJoins.add(new InnerJoinExpression(middleTable, sourcePath, this.sqlQuery));
// add the target table to the query
this.innerJoins.add(new InnerJoinExpression(targetTableName, targetPath, this.sqlQuery));
criteria.add(buffer.toString());
}
protected void getConditionManyToOneRelation(IDOEntityDefinition sourceDefinition, String sourcePath, IDOEntityDefinition targetDefinition, String targetPath, String pathElement, List criteria) throws IDOCompositePrimaryKeyException {
String targetPrimaryKeyColumnName = targetDefinition.getPrimaryKeyDefinition().getField().getSQLFieldName();
String targetTableName = targetDefinition.getSQLTableName();
String sourceTableName = sourceDefinition.getSQLTableName();
// get aliases
String aliasSourceTableName = this.sqlQuery.getUniqueNameForEntityByTableName(sourceTableName, sourcePath);
String aliasTargetTableName = this.sqlQuery.getUniqueNameForEntityByTableName(targetTableName, targetPath);
// build the condition
StringBuffer buffer = new StringBuffer(aliasSourceTableName);
buffer.append('.').append(pathElement);
buffer.append("=");
buffer.append(aliasTargetTableName).append('.');
buffer.append(targetPrimaryKeyColumnName);
// add the target table to the query
this.innerJoins.add(new InnerJoinExpression(targetTableName, targetPath, this.sqlQuery));
criteria.add(buffer.toString());
}
private IDOEntityDefinition lookForTargetEntityAmongManyToManyRelations(IDOEntityDefinition definition, String pathElement) {
List manyToManyEntities = Arrays.asList(definition.getManyToManyRelatedEntities());
Iterator manyToManyEntitiesIterator = manyToManyEntities.iterator();
while (manyToManyEntitiesIterator.hasNext()) {
IDOEntityDefinition def = (IDOEntityDefinition) manyToManyEntitiesIterator.next();
String className = def.getInterfaceClass().getName();
if (pathElement.equals(className)) {
return def;
}
}
return null;
}
private IDOEntityDefinition lookForTargetEntityAmongManyToOneRelations(IDOEntityDefinition definition, String pathElement)
throws ExpressionException {
List fields = Arrays.asList(definition.getFields());
Iterator fieldsIterator = fields.iterator();
while (fieldsIterator.hasNext()) {
IDOEntityField field = (IDOEntityField) fieldsIterator.next();
if (field.isPartOfManyToOneRelationship() && field.getSQLFieldName().equalsIgnoreCase(pathElement)) {
IDOEntityDefinition def = null;
try {
def = field.getManyToOneRelated();
return def;
}
catch (IDORelationshipException ex) {
String message = "[" + this.getClass().getName() + "] Problem occured during investigation of the following field: " +
pathElement + " Message is: " + ex.getMessage();
System.err.println(message);
ex.printStackTrace(System.err);
String text = "[" + this.getClass().getName() + "] Path element could not be resolved.";
throw new ExpressionException(text);
}
}
}
return null;
}
private IDOEntity getInstance(String className) throws ExpressionException {
Class entityClass = null;
try {
entityClass = RefactorClassRegistry.forName(className);
}
catch (ClassNotFoundException ex) {
//TODO: thi add exception handling
String message = "[" + this.getClass().getName() + "] Class could not be found";
throw new ExpressionException(message);
}
IDOEntity idoEntity = GenericEntity.getStaticInstanceIDO(entityClass);
return idoEntity;
}
public List getInnerJoins() {
return this.innerJoins;
}
public List getCriteria() {
return this.criteriaList;
}
public boolean hasCriteria() {
return !(this.criteriaList == null || this.criteriaList.isEmpty());
}
public String toSQLString() {
StringBuffer buffer = new StringBuffer();
Iterator criteriaListIterator = this.criteriaList.iterator();
boolean addAnd = false;
while (criteriaListIterator.hasNext()) {
if (addAnd) {
buffer.append(" AND ");
}
else {
addAnd = true;
}
String criteria = (String) criteriaListIterator.next();
buffer.append(criteria);
}
return buffer.toString();
}
public boolean isValid() {
return true;
// think about that
//return (criteriaList != null && innerJoins != null);
}
/* (non-Javadoc)
* @see com.idega.block.dataquery.data.sql.DynamicExpression#isDynamic()
*/
public boolean isDynamic() {
return false;
}
/* (non-Javadoc)
* @see com.idega.block.dataquery.data.sql.DynamicExpression#getIdentifier()
*/
public Map getIdentifierValueMap() {
// never used because isDynamic returns always false
return null;
}
public Map getIdentifierInputDescriptionMap() {
// never used because isDynamic returns always false
return null;
}
public void setIdentifierValueMap(Map identifierValueMap) {
// never used because isDynamic returns always false
}
}