1 27 package org.objectweb.speedo.query.parser; 28 29 import java.util.ArrayList ; 30 import java.util.HashMap ; 31 import java.util.HashSet ; 32 import java.util.List ; 33 import java.util.Map ; 34 import java.util.Stack ; 35 36 import javax.jdo.JDOUserException; 37 38 import org.objectweb.jorm.metainfo.api.Class; 39 import org.objectweb.jorm.metainfo.api.Manager; 40 import org.objectweb.medor.api.Field; 41 import org.objectweb.medor.api.MedorException; 42 import org.objectweb.medor.query.api.QueryTree; 43 import org.objectweb.medor.query.api.QueryTreeField; 44 import org.objectweb.medor.query.jorm.lib.ClassExtent; 45 import org.objectweb.medor.query.jorm.lib.PNameField; 46 import org.objectweb.medor.query.jorm.lib.QueryBuilder; 47 import org.objectweb.speedo.api.SpeedoException; 48 import org.objectweb.util.monolog.api.BasicLevel; 49 import org.objectweb.util.monolog.api.Logger; 50 51 54 public class SpeedoQLVariableVisitor extends SpeedoQLAbstractVisitor { 55 56 private Manager jmiManager; 57 58 59 67 private Map ids = new HashMap (); 68 69 private HashSet testcontains = new HashSet (); 70 private HashSet isEmptys = new HashSet (); 71 72 75 private QueryTree qt = null; 76 77 80 private SimpleNode speedoql = null; 81 82 private int nbNot = 0; 83 84 private List orders; 85 86 89 private HashMap fields = new HashMap (); 90 91 private QueryBuilder qb = new QueryBuilder(); 92 93 private boolean includeSubClasses; 94 95 public SpeedoQLVariableVisitor(SimpleNode speedoql, 96 Manager jmim, 97 Logger logger, 98 Map hparam, 99 Map hvar, 100 List orders, 101 String classname, 102 boolean includeSubClasses 103 ) throws SpeedoException { 104 this.speedoql = speedoql; 105 this.jmiManager= jmim; 106 setLogger(logger); 107 setParams(hparam); 108 setVars(hvar); 109 setOrders(orders); 110 setCurrentClass(classname); 111 this.includeSubClasses = includeSubClasses; 112 startVisiting(); 113 } 114 115 public Map getFields() { 116 return fields; 117 } 118 119 public QueryBuilder getQueryBuilder() { 120 return qb; 121 } 122 123 public QueryTree getQueryTree() { 124 return qb.getQueryTree(); 125 } 126 127 public void setOrders(List orders) { 128 this.orders = orders; 129 } 130 131 136 public Map startVisiting() throws SpeedoException { 137 debug = logger != null && logger.isLoggable(BasicLevel.DEBUG); 138 nbNot = 0; 139 140 if (curClass != null) { 142 logger.log(BasicLevel.DEBUG, "create a new IdValue object " + 143 "with the current class (" + curClass + ")"); 144 IdValue iv = new IdValue(new String [] {curClass}, EXTENT); 145 iv.alias = "this"; 146 ids.put(iv.alias, iv); 147 } 148 try { 149 visit(speedoql); 151 } catch (Exception e) { 152 throw new SpeedoException("Error during the parsing of JDOQL:", e); 153 } 154 if (orders != null) { 155 for(int i=0; i<orders.size(); i++) { 156 String fieldName = (String ) orders.get(i); 157 int idx = fieldName.indexOf(' '); 158 if (idx != -1) { 159 fieldName = fieldName.substring(0, idx).trim(); 160 } 161 visitPath(null, fieldName); 162 } 163 } 164 ArrayList toTreat = new ArrayList (ids.values()); 165 while(!toTreat.isEmpty()) { 166 treatIdValue((IdValue) toTreat.get(0), toTreat); 167 } 168 return fields; 169 } 170 private void treatIdValue(IdValue iv, List toTreat) throws SpeedoException { 171 if (iv.nameType != EXTENT) { 172 IdValue dependency = (IdValue) ids.get(iv.name[0]); 173 if (dependency == null) { 174 throw new SpeedoException("Dependency unresolved: " + iv.name[0]); 175 } 176 if (toTreat.contains(dependency)) { 177 treatIdValue(dependency, toTreat); 178 } 179 } 180 toTreat.remove(iv); 181 182 QueryBuilder theqb = qb; 183 if (iv.nameType == MEMBEROF) { 184 String rest = mergePath(iv.name, 1, iv.name.length - 1); 186 theqb = new QueryBuilder(qb); 187 try { 188 theqb.define("", qb.navigate(iv.name[0])); 189 } catch (MedorException e) { 190 throw new SpeedoException(e); 191 } 192 } 193 194 try { 195 String n = iv.alias + "." + Field.PNAMENAME; 196 fields.put(n, theqb.project(iv.alias, define(theqb, iv.alias, iv.alias))); 197 for (int i = 0; i < iv.getDeclaredPathLength(); i++) { 198 String path = iv.getMergedPath(i); 199 if (!testcontains.contains(path) && !isEmptys.contains(path)) { 200 fields.put(path, theqb.project(path, define(theqb, path, null))); 201 } 202 } 203 } catch (Exception e) { 204 throw new SpeedoException("Error during the parsing of JDOQL:", e); 205 } 206 } 207 public QueryTreeField getField(String path) throws SpeedoException { 208 String [] splitted = splitPath(path); 209 if (params != null && params.containsKey(splitted[0])) { 210 if (splitted.length > 1) { 211 } 213 } else if (vars != null && vars.containsKey(splitted[0])) { 214 } else { if (!splitted[0].equals("this")) { 216 path = "this." + path; 217 String [] newsplitted = new String [splitted.length + 1]; 218 newsplitted[0] = "this"; 219 System.arraycopy(splitted, 0, newsplitted, 1, splitted.length); 220 splitted = newsplitted; 221 } 222 } 223 QueryTreeField qtf = (QueryTreeField) fields.get(path); 224 if (qtf == null) { 225 try { 226 qtf = qb.project(define(qb, path, null)); 227 } catch (Exception e) { 228 throw new SpeedoException(e); 229 } 230 fields.put(path, qtf); 231 } 232 return qtf; 233 } 234 private QueryTreeField define(QueryBuilder theqb, String id, String alias) throws ParseException, MedorException { 235 String [] path = splitPath(id); 236 237 if (!theqb.contains(path[0])) { 238 IdValue idv = (IdValue) ids.get(path[0]); 239 String [] name = idv.name; 240 241 PNameField pnf; 242 if (name.length == 1) { 243 pnf = extent(name[0], path[0]); 244 theqb.define(path[0], pnf); 245 } else { 246 pnf = (PNameField) define(theqb, mergePath(name), alias); 247 if (!path[0].equals(alias)) { 248 theqb.define(path[0], pnf); 249 } 250 } 251 } 252 253 return theqb.navigate(path,alias); 254 } 255 256 private PNameField extent(String classname, String alias) throws ParseException, MedorException { 257 if (classname == null) { 258 throw new NullPointerException ("class name not defined"); 259 } 260 Class theClass = jmiManager.getClass(classname); 261 if (theClass == null) { 262 throw new ParseException 263 ("Class '" + classname + 264 "' has not been declared in the jorm meta information"); 265 } 266 ClassExtent ext = new ClassExtent(theClass, alias, Field.PNAMENAME, false); 267 if (classname.equals(this.curClass)) { 268 ext.setWithSubClasses(includeSubClasses); 269 } 270 return (PNameField) ext.getField(ext.getPNameFieldName()); 271 } 272 273 274 277 278 public Object visit(ASTSpeedoPrimary node, Object data) { 279 visit((SimpleNode) node, data); 280 return null; 281 } 282 283 public Object visit(ASTSpeedoQL node, Object data) { 284 visit((SimpleNode) node, data); 285 return null; 286 } 287 288 public Object visit(ASTPrimary node, Object data) { 289 visit((SimpleNode) node, data); 290 return null; 291 } 292 293 public Object visit(ASTRelationalExpression node, Object data) { 294 visit((SimpleNode) node, data); 295 return null; 296 } 297 298 public Object visit(ASTAdditiveExpression node, Object data) { 299 300 visit((SimpleNode) node, data); 301 return null; 302 } 303 304 public Object visit(ASTUnaryExpression node, Object data) { 305 boolean hasNot = node.ops.size() > 0 306 && ((Integer ) node.ops.get(0)).intValue() == SpeedoQLConstants.NOT; 307 if (hasNot) { 308 nbNot ++; 309 if (debug) { 310 logger.log(BasicLevel.DEBUG, "remember a Not: "+ nbNot); 311 } 312 } 313 visit((SimpleNode) node, data); 314 if (hasNot && nbNot> 0) { 315 nbNot--; 316 if (debug) { 317 logger.log(BasicLevel.DEBUG, "forget a Not: "+ nbNot); 318 } 319 } 320 return null; 322 } 323 324 public Object visit(ASTCastExpression node, Object data) { 325 return null; 326 } 327 328 public Object visit(ASTArgumentList node, Object data) { 329 visit((SimpleNode) node, data); 330 return null; 331 } 332 333 public Object visit(ASTLiteral node, Object data) { 334 visit((SimpleNode) node, data); 335 return null; 336 } 337 338 public Object visit(ASTType node, Object data) { 339 visit((SimpleNode) node, data); 341 return null; 342 } 343 344 public Object visit(ASTQualifiedName node, Object data) { 345 Stack stack = (Stack ) data; 346 String name = (String ) node.value; 347 if (debug) { 348 logger.log(BasicLevel.DEBUG, "variable visitor: qualifiedname=<" + name + ">"); 349 } 350 visitPath(stack, name); 351 if (debug) { 352 logger.log(BasicLevel.DEBUG, "variable visitor: qualifiedname=<" + name + ">-end"); 353 } 354 return null; 355 } 356 357 private void visitPath(Stack stack, String path) { 358 String [] splitted = splitPath(path); 359 if (params != null && params.containsKey(splitted[0])) { 360 visitParameterUse(stack, splitted); 361 } else if (vars != null && vars.containsKey(splitted[0])) { 362 visitVariableUse(stack, path, splitted); 363 } else { if (!splitted[0].equals("this")) { 365 path = "this." + path; 366 String [] newsplitted = new String [splitted.length + 1]; 367 newsplitted[0] = "this"; 368 System.arraycopy(splitted, 0, newsplitted, 1, splitted.length); 369 splitted = newsplitted; 370 } 371 visitThisUse(stack, path, splitted); 372 } 373 } 374 375 380 private void visitParameterUse(Stack stack, String [] splitted) { 381 if (stack.size() > 0 && stack.peek() instanceof String ) { 382 String setpath = (String ) stack.pop(); 383 if (debug) { 384 logger.log(BasicLevel.DEBUG, "The parameter '" + splitted[0] 385 + "' is used in a contains expression: " 386 + setpath + ".contains(" + splitted[0] + ")"); 387 } 388 } else if (debug) { 389 logger.log(BasicLevel.DEBUG, "Use of the parameter " + splitted[0]); 390 } 391 } 392 393 399 private void visitVariableUse(Stack stack, String path, String [] splitted) { 400 if (debug) { 401 logger.log(BasicLevel.DEBUG, "Use of the variable " + splitted[0] 402 + " : " + path); 403 } 404 IdValue iv = (IdValue) ids.get(splitted[0]); 406 if (iv == null) { 407 if (debug) { 408 logger.log(BasicLevel.DEBUG, "Create a new IdValue for the variable " + splitted[0] + " for the path " + path); 409 } 410 iv = new IdValue(); 411 iv.nameType = EXTENT; 414 iv.alias = splitted[0]; 415 ids.put(iv.alias, iv); 416 } else { 417 if (iv.alias !=null && !iv.alias.equals(splitted[0])) { 418 logger.log(BasicLevel.WARN, 419 "Redefine a different alias for a variable, old=" 420 + iv.alias + ", new=" + splitted[0]); 421 } 422 iv.alias = splitted[0]; 423 if (debug) { 424 logger.log(BasicLevel.DEBUG, "Use the IdValue of the variable " + splitted[0] + " by the path " + path); 425 } 426 } 427 if (stack.size() > 0 && stack.peek() instanceof String ) { 428 String definition = (String ) stack.pop(); 430 if (debug) { 431 logger.log(BasicLevel.DEBUG, "Define the variable " + splitted[0] 432 + " to " + definition); 433 } 434 if (iv.name != null) { 435 throw new JDOUserException("Variable '" 436 + splitted[0] + "' defined several times : \n\t" 437 + iv.name + "\n\t" + definition); 438 } 439 iv.nameType = ((nbNot%2)==1 ? MEMBEROF : NAVIGATION); 440 iv.name = splitPath(definition); 441 testcontains.add(definition); 442 } 443 visitThisOrVarUseEnd(stack, path, splitted); 444 } 445 446 private void visitThisUse(Stack stack, String path, String [] splitted) { 447 if (debug) { 448 logger.log(BasicLevel.DEBUG, "Use of this " + splitted[0] 449 + " : " + path); 450 } 451 IdValue iv = (IdValue) ids.get(splitted[0]); 452 if (stack != null && stack.size() > 0 && stack.peek() instanceof String ) { 453 String collectionpath = (String ) stack.pop(); 455 if (debug) { 456 logger.log(BasicLevel.DEBUG, "test collection membering " + path 457 + " IN " + collectionpath); 458 } 459 testcontains.add(collectionpath); 460 } 461 visitThisOrVarUseEnd(stack, path, splitted); 462 463 } 464 471 private void visitThisOrVarUseEnd(Stack stack, String path, String [] splitted) { 472 int operatorId = isMethodOperator(splitted[splitted.length - 1]); 473 if (operatorId != -1) { 474 String begin = buildStringwithout(splitted, splitted.length-1, "."); 476 ((IdValue) ids.get(splitted[0])).addPath(begin); 477 switch(operatorId) { 478 case CONTAINS_OPERATOR: 479 if (debug) { 480 logger.log(BasicLevel.DEBUG, "contains case, path: " + begin); 481 } 482 if (stack != null) { 484 stack.push(begin); 485 } 486 break; 487 case IS_EMPTY_OPERATOR: 488 if (debug) { 489 logger.log(BasicLevel.DEBUG, "isEmpty case, path: " + begin); 490 } 491 isEmptys.add(begin); 492 break; 493 } 494 return; 495 } else { 496 if (debug) { 497 logger.log(BasicLevel.DEBUG, 498 "Navigation case without operator, path:" + path); 499 } 500 ((IdValue) ids.get(splitted[0])).addPath(path); 501 } 502 } 503 504 } 505 | Popular Tags |