1 19 package org.apache.cayenne.access.jdbc; 20 21 import java.util.HashMap ; 22 import java.util.Iterator ; 23 import java.util.List ; 24 import java.util.Map ; 25 26 import org.apache.cayenne.ejbql.EJBQLBaseVisitor; 27 import org.apache.cayenne.ejbql.EJBQLException; 28 import org.apache.cayenne.ejbql.EJBQLExpression; 29 import org.apache.cayenne.ejbql.parser.EJBQLIdentificationVariable; 30 import org.apache.cayenne.ejbql.parser.EJBQLIdentifier; 31 import org.apache.cayenne.ejbql.parser.EJBQLInnerJoin; 32 import org.apache.cayenne.ejbql.parser.EJBQLPath; 33 import org.apache.cayenne.map.DbEntity; 34 import org.apache.cayenne.map.DbJoin; 35 import org.apache.cayenne.map.DbRelationship; 36 import org.apache.cayenne.map.ObjAttribute; 37 import org.apache.cayenne.map.ObjEntity; 38 import org.apache.cayenne.map.ObjRelationship; 39 import org.apache.cayenne.reflect.ClassDescriptor; 40 41 47 abstract class EJBQLPathTranslator extends EJBQLBaseVisitor { 48 49 private EJBQLTranslationContext context; 50 protected ObjEntity currentEntity; 51 private String lastPathComponent; 52 protected String lastAlias; 53 protected String idPath; 54 protected String joinMarker; 55 private String fullPath; 56 private EJBQLFromTranslator joinAppender; 57 58 EJBQLPathTranslator(EJBQLTranslationContext context) { 59 super(true); 60 this.context = context; 61 } 62 63 protected abstract void appendMultiColumnPath(EJBQLMultiColumnOperand operand); 64 65 public boolean visitPath(EJBQLPath expression, int finishedChildIndex) { 66 67 if (finishedChildIndex > 0) { 68 69 if (finishedChildIndex + 1 < expression.getChildrenCount()) { 70 processIntermediatePathComponent(); 71 } 72 else { 73 processLastPathComponent(); 74 } 75 } 76 77 return true; 78 } 79 80 public boolean visitIdentifier(EJBQLExpression expression) { 81 ClassDescriptor descriptor = context.getCompiledExpression().getEntityDescriptor( 82 expression.getText()); 83 if (descriptor == null) { 84 throw new EJBQLException("Invalid identification variable: " 85 + expression.getText()); 86 } 87 88 this.currentEntity = descriptor.getEntity(); 89 this.idPath = expression.getText(); 90 this.joinMarker = EJBQLFromTranslator.makeJoinTailMarker(idPath); 91 this.fullPath = idPath; 92 return true; 93 } 94 95 public boolean visitIdentificationVariable(EJBQLExpression expression) { 96 97 if (lastPathComponent != null) { 100 resolveJoin(); 101 } 102 103 this.lastPathComponent = expression.getText(); 104 return true; 105 } 106 107 private EJBQLFromTranslator getJoinAppender() { 108 if (joinAppender == null) { 109 joinAppender = new EJBQLFromTranslator(context); 110 } 111 112 return joinAppender; 113 } 114 115 private void resolveJoin() { 116 117 String newPath = idPath + '.' + lastPathComponent; 118 String oldPath = context.registerReusableJoin(idPath, lastPathComponent, newPath); 119 120 this.fullPath = fullPath + '.' + lastPathComponent; 121 122 if (oldPath != null) { 123 this.idPath = oldPath; 124 this.lastAlias = context.getTableAlias(oldPath, currentEntity 125 .getDbEntityName()); 126 } 127 else { 128 EJBQLIdentifier id = new EJBQLIdentifier(-1); 130 id.setText(idPath); 131 132 EJBQLIdentificationVariable idVar = new EJBQLIdentificationVariable(-1); 133 idVar.setText(lastPathComponent); 134 135 EJBQLPath path = new EJBQLPath(-1); 136 path.jjtAddChild(id, 0); 137 path.jjtAddChild(idVar, 1); 138 139 EJBQLIdentifier joinId = new EJBQLIdentifier(-1); 140 joinId.setText(fullPath); 141 142 EJBQLInnerJoin join = new EJBQLInnerJoin(-1); 143 join.jjtAddChild(path, 0); 144 join.jjtAddChild(joinId, 1); 145 146 context.switchToMarker(joinMarker); 147 148 getJoinAppender().visitInnerJoin(join); 149 context.switchToMainBuffer(); 150 151 this.idPath = newPath; 152 this.lastAlias = context.getTableAlias(fullPath, currentEntity 153 .getDbEntityName()); 154 } 155 } 156 157 private void processIntermediatePathComponent() { 158 ObjRelationship relationship = (ObjRelationship) currentEntity 159 .getRelationship(lastPathComponent); 160 if (relationship == null) { 161 throw new EJBQLException("Unknown relationship '" 162 + lastPathComponent 163 + "' for entity '" 164 + currentEntity.getName() 165 + "'"); 166 } 167 168 this.currentEntity = (ObjEntity) relationship.getTargetEntity(); 169 } 170 171 private void processLastPathComponent() { 172 173 ObjAttribute attribute = (ObjAttribute) currentEntity 174 .getAttribute(lastPathComponent); 175 176 if (attribute != null) { 177 processTerminatingAttribute(attribute); 178 return; 179 } 180 181 ObjRelationship relationship = (ObjRelationship) currentEntity 182 .getRelationship(lastPathComponent); 183 if (relationship != null) { 184 processTerminatingRelationship(relationship); 185 return; 186 } 187 188 throw new IllegalStateException ("Invalid path component: " + lastPathComponent); 189 } 190 191 protected void processTerminatingAttribute(ObjAttribute attribute) { 192 193 DbEntity table = currentEntity.getDbEntity(); 194 String alias = this.lastAlias != null ? lastAlias : context.getTableAlias( 195 idPath, 196 table.getFullyQualifiedName()); 197 context.append(' ').append(alias).append('.').append( 198 attribute.getDbAttributeName()); 199 } 200 201 private void processTerminatingRelationship(ObjRelationship relationship) { 202 203 if (relationship.isSourceIndependentFromTargetChange()) { 205 } 207 else { 208 210 DbRelationship dbRelationship = (DbRelationship) relationship 212 .getDbRelationships() 213 .get(0); 214 DbEntity table = (DbEntity) dbRelationship.getSourceEntity(); 215 216 String alias = this.lastAlias != null ? lastAlias : context.getTableAlias( 217 idPath, 218 table.getFullyQualifiedName()); 219 220 List joins = dbRelationship.getJoins(); 221 222 if (joins.size() == 1) { 223 DbJoin join = (DbJoin) joins.get(0); 224 context 225 .append(' ') 226 .append(alias) 227 .append('.') 228 .append(join.getSourceName()); 229 } 230 else { 231 Map multiColumnMatch = new HashMap (joins.size() + 2); 232 233 Iterator it = joins.iterator(); 234 while (it.hasNext()) { 235 DbJoin join = (DbJoin) it.next(); 236 String column = alias + "." + join.getSourceName(); 237 238 multiColumnMatch.put(join.getTargetName(), column); 239 } 240 241 appendMultiColumnPath(EJBQLMultiColumnOperand.getPathOperand( 242 context, 243 multiColumnMatch)); 244 } 245 } 246 } 247 } 248 | Popular Tags |