1 19 package org.apache.cayenne.ejbql.parser; 20 21 import java.util.ArrayList ; 22 import java.util.Collection ; 23 import java.util.HashMap ; 24 import java.util.Iterator ; 25 import java.util.Map ; 26 27 import org.apache.cayenne.ejbql.EJBQLBaseVisitor; 28 import org.apache.cayenne.ejbql.EJBQLCompiledExpression; 29 import org.apache.cayenne.ejbql.EJBQLException; 30 import org.apache.cayenne.ejbql.EJBQLExpression; 31 import org.apache.cayenne.ejbql.EJBQLExpressionVisitor; 32 import org.apache.cayenne.map.EntityResolver; 33 import org.apache.cayenne.map.ObjRelationship; 34 import org.apache.cayenne.query.SQLResultSetMapping; 35 import org.apache.cayenne.reflect.ArcProperty; 36 import org.apache.cayenne.reflect.ClassDescriptor; 37 import org.apache.cayenne.reflect.Property; 38 39 45 class Compiler { 46 47 private String rootId; 48 private EntityResolver resolver; 49 private Map descriptorsById; 50 private Map incomingById; 51 private Collection paths; 52 private EJBQLExpressionVisitor fromItemVisitor; 53 private EJBQLExpressionVisitor joinVisitor; 54 private EJBQLExpressionVisitor pathVisitor; 55 private EJBQLExpressionVisitor rootDescriptorVisitor; 56 private SQLResultSetMapping resultSetMapping; 57 58 Compiler(EntityResolver resolver) { 59 this.resolver = resolver; 60 this.descriptorsById = new HashMap (); 61 this.incomingById = new HashMap (); 62 63 this.rootDescriptorVisitor = new SelectExpressionVisitor(); 64 this.fromItemVisitor = new FromItemVisitor(); 65 this.joinVisitor = new JoinVisitor(); 66 this.pathVisitor = new PathVisitor(); 67 } 68 69 CompiledExpression compile(String source, EJBQLExpression parsed) { 70 parsed.visit(new CompilationVisitor()); 71 72 if (paths != null) { 74 Iterator it = paths.iterator(); 75 while (it.hasNext()) { 76 EJBQLPath path = (EJBQLPath) it.next(); 77 String id = normalizeIdPath(path.getId()); 78 79 ClassDescriptor descriptor = (ClassDescriptor) descriptorsById.get(id); 80 if (descriptor == null) { 81 throw new EJBQLException("Unmapped id variable: " + id); 82 } 83 84 StringBuffer buffer = new StringBuffer (id); 85 86 for (int i = 1; i < path.getChildrenCount(); i++) { 87 88 String pathChunk = path.getChild(i).getText(); 89 buffer.append('.').append(pathChunk); 90 91 Property property = descriptor.getProperty(pathChunk); 92 if (property instanceof ArcProperty) { 93 ObjRelationship incoming = ((ArcProperty) property) 94 .getRelationship(); 95 descriptor = ((ArcProperty) property).getTargetDescriptor(); 96 String pathString = buffer.substring(0, buffer.length()); 97 98 descriptorsById.put(pathString, descriptor); 99 incomingById.put(pathString, incoming); 100 } 101 } 102 } 103 } 104 105 CompiledExpression compiled = new CompiledExpression(); 106 compiled.setExpression(parsed); 107 compiled.setSource(source); 108 109 compiled.setRootId(rootId); 110 compiled.setDescriptorsById(descriptorsById); 111 compiled.setIncomingById(incomingById); 112 compiled.setResultSetMapping(resultSetMapping); 113 114 return compiled; 115 } 116 117 private void addPath(EJBQLPath path) { 118 if (paths == null) { 119 paths = new ArrayList (); 120 } 121 122 paths.add(path); 123 } 124 125 static String normalizeIdPath(String idPath) { 126 127 129 int pathSeparator = idPath.indexOf('.'); 130 return pathSeparator < 0 ? idPath.toLowerCase() : idPath.substring( 131 0, 132 pathSeparator).toLowerCase() 133 + idPath.substring(pathSeparator); 134 } 135 136 class CompilationVisitor extends EJBQLBaseVisitor { 137 138 public boolean visitSelectExpression(EJBQLExpression expression) { 139 expression.visit(rootDescriptorVisitor); 140 return false; 141 } 142 143 public boolean visitFromItem(EJBQLFromItem expression) { 144 expression.visit(fromItemVisitor); 145 return false; 146 } 147 148 public boolean visitInnerFetchJoin(EJBQLJoin join) { 149 join.visit(joinVisitor); 150 return false; 151 } 152 153 public boolean visitInnerJoin(EJBQLJoin join) { 154 join.visit(joinVisitor); 155 return false; 156 } 157 158 public boolean visitOuterFetchJoin(EJBQLJoin join) { 159 join.visit(joinVisitor); 160 return false; 161 } 162 163 public boolean visitOuterJoin(EJBQLJoin join) { 164 join.visit(joinVisitor); 165 return false; 166 } 167 168 public boolean visitWhere(EJBQLExpression expression) { 169 expression.visit(pathVisitor); 170 return false; 171 } 172 173 public boolean visitOrderBy(EJBQLExpression expression) { 174 expression.visit(pathVisitor); 175 return false; 176 } 177 } 178 179 class FromItemVisitor extends EJBQLBaseVisitor { 180 181 private String entityName; 182 183 public boolean visitIdentificationVariable(EJBQLExpression expression) { 184 entityName = expression.getText(); 185 return true; 186 } 187 188 public boolean visitIdentifier(EJBQLExpression expression) { 189 190 String rootId = normalizeIdPath(expression.getText()); 192 193 ClassDescriptor descriptor = resolver.getClassDescriptor(entityName); 195 if (descriptor == null) { 196 throw new EJBQLException("Unmapped abstract schema name: " + entityName); 197 } 198 199 ClassDescriptor old = (ClassDescriptor) descriptorsById.put( 200 rootId, 201 descriptor); 202 if (old != null && old != descriptor) { 203 throw new EJBQLException("Duplicate identification variable definition: " 204 + rootId 205 + ", it is already used for " 206 + old.getEntity().getName()); 207 } 208 209 if (Compiler.this.rootId == null) { 211 Compiler.this.rootId = rootId; 212 } 213 214 return true; 215 } 216 } 217 218 class JoinVisitor extends EJBQLBaseVisitor { 219 220 private String id; 221 private ObjRelationship incoming; 222 private ClassDescriptor descriptor; 223 224 public boolean visitPath(EJBQLPath expression, int finishedChildIndex) { 225 if (finishedChildIndex + 1 < expression.getChildrenCount()) { 226 this.id = expression.getId(); 227 this.descriptor = (ClassDescriptor) descriptorsById.get(id); 228 229 if (descriptor == null) { 230 throw new EJBQLException("Unmapped id variable: " + id); 231 } 232 } 233 234 return true; 235 } 236 237 public boolean visitIdentificationVariable(EJBQLExpression expression) { 238 Property property = descriptor.getProperty(expression.getText()); 239 if (property instanceof ArcProperty) { 240 incoming = ((ArcProperty) property).getRelationship(); 241 descriptor = ((ArcProperty) property).getTargetDescriptor(); 242 } 243 else { 244 throw new EJBQLException("Incorrect relationship path: " 245 + expression.getText()); 246 } 247 248 return true; 249 } 250 251 public boolean visitIdentifier(EJBQLExpression expression) { 252 if (incoming != null) { 253 254 String aliasId = expression.getText(); 255 256 ClassDescriptor old = (ClassDescriptor) descriptorsById.put( 258 aliasId, 259 descriptor); 260 if (old != null && old != descriptor) { 261 throw new EJBQLException( 262 "Duplicate identification variable definition: " 263 + aliasId 264 + ", it is already used for " 265 + old.getEntity().getName()); 266 } 267 268 incomingById.put(aliasId, incoming); 269 270 id = null; 271 descriptor = null; 272 incoming = null; 273 } 274 275 return true; 276 } 277 } 278 279 class PathVisitor extends EJBQLBaseVisitor { 280 281 public boolean visitPath(EJBQLPath expression, int finishedChildIndex) { 282 addPath(expression); 283 return false; 284 } 285 } 286 287 class SelectExpressionVisitor extends EJBQLBaseVisitor { 288 289 public boolean visitIdentifier(EJBQLExpression expression) { 290 rootId = normalizeIdPath(expression.getText()); 291 return false; 292 } 293 294 public boolean visitAggregate(EJBQLExpression expression) { 295 addResultSetColumn(); 296 return false; 297 } 298 299 public boolean visitPath(EJBQLPath expression, int finishedChildIndex) { 300 addPath(expression); 301 addResultSetColumn(); 302 return false; 303 } 304 305 private void addResultSetColumn() { 306 if (resultSetMapping == null) { 307 resultSetMapping = new SQLResultSetMapping(); 308 } 309 310 String column = "sc" + resultSetMapping.getColumnResults().size(); 311 resultSetMapping.addColumnResult(column); 312 } 313 } 314 } | Popular Tags |