1 23 24 package org.objectweb.medor.query.jorm.lib; 25 26 import java.util.ArrayList ; 27 import java.util.Collections ; 28 29 import org.objectweb.jorm.metainfo.api.Class; 30 import org.objectweb.jorm.metainfo.api.ClassRef; 31 import org.objectweb.jorm.metainfo.api.GenClassRef; 32 import org.objectweb.jorm.metainfo.api.Reference; 33 import org.objectweb.jorm.metainfo.api.TypedElement; 34 import org.objectweb.medor.api.Field; 35 import org.objectweb.medor.api.MedorException; 36 import org.objectweb.medor.api.TupleStructure; 37 import org.objectweb.medor.expression.api.Expression; 38 import org.objectweb.medor.expression.api.MalformedExpressionException; 39 import org.objectweb.medor.expression.api.Operand; 40 import org.objectweb.medor.expression.api.TypingException; 41 import org.objectweb.medor.expression.lib.And; 42 import org.objectweb.medor.expression.lib.Equal; 43 import org.objectweb.medor.expression.lib.Not; 44 import org.objectweb.medor.filter.api.FieldOperand; 45 import org.objectweb.medor.filter.jorm.lib.NavigatorOperator; 46 import org.objectweb.medor.filter.lib.BasicFieldOperand; 47 import org.objectweb.medor.filter.lib.ExpressionPrinter; 48 import org.objectweb.medor.filter.lib.MemberOf; 49 import org.objectweb.medor.lib.Log; 50 import org.objectweb.medor.query.api.PropagatedField; 51 import org.objectweb.medor.query.api.QueryNode; 52 import org.objectweb.medor.query.api.QueryTree; 53 import org.objectweb.medor.query.api.QueryTreeField; 54 import org.objectweb.medor.query.jorm.api.JormExtent; 55 import org.objectweb.medor.query.lib.JoinProject; 56 import org.objectweb.medor.query.lib.QueryTreePrinter; 57 import org.objectweb.util.monolog.api.BasicLevel; 58 import org.objectweb.util.monolog.api.Logger; 59 60 66 public class NavigatorNodeFactory { 67 68 public final static String PNAME_FIELD_NAME = "object"; 69 private static int pnameFieldNameIndex = 0; 70 71 public final static String GENCLASS_ELEMENT_NAME = "element"; 72 73 76 public final static byte NAVIGATION = 1; 77 82 public final static byte NAVIGATION_INTO_LAST = 2; 83 84 88 public final static byte IS_EMPTY = 4; 89 93 public final static byte IS_NOT_EMPTY = 8; 94 95 public static Logger logger = Log.getLoggerFactory() 96 .getLogger("org.objectweb.medor.query.jorm.NavigatorNodeFactory"); 97 98 113 public static QueryTreeField navigate(NavigatorOperator nav, 114 String aliasName, 115 byte operation) 116 throws MedorException { 117 QueryTreeField qtf = null; 119 PNameField pnf = null; 121 byte op = NAVIGATION; 123 boolean joinAlreadyConstructed = false; 124 String fieldName = null; 125 try { 126 fieldName = ((Operand) nav.getExpression(1)).getString(); 127 } catch (TypingException te) { 128 throw new MedorException(te); 129 } 130 logger.log(BasicLevel.DEBUG, "navigate(" + aliasName + ", " 131 + ExpressionPrinter.e2str(nav.getExpression(0)) + ", " + fieldName 132 + ", op:" + op + ")"); 133 134 ArrayList path = new ArrayList (); 136 path.add(nav.getFieldOperand()); 137 path = nav.getPath(path); 138 139 for (int j = 0; j < path.size() - 1; j++) { 140 141 boolean propagQtf; 142 if (j == path.size() - 2) { 145 op = operation; 146 } 147 Object element = path.get(j); 148 if (element instanceof FieldOperand) { 149 qtf = (QueryTreeField) ((FieldOperand) element).getField(); 150 pnf = getPNameField(qtf); 151 logger.log(BasicLevel.DEBUG, "Navigation from FieldOperand " + qtf.getName()); 152 propagQtf = true; 153 } else { 154 propagQtf = true; 157 logger.log(BasicLevel.DEBUG, "Further navigation for " + element); 158 } 161 162 fieldName = (String ) path.get(j + 1); 163 logger.log(BasicLevel.DEBUG, "Navigate to " + fieldName); 164 165 logger.log(BasicLevel.DEBUG, "propagQtf=" + propagQtf); 166 logger.log(BasicLevel.DEBUG, "qtf=" + qtf.getName() + " of node " + qtf.getQueryTree()); 167 if (pnf == null) 168 throw new MedorException("Impossible to find a PNameField"); 169 170 QueryTree qt = qtf.getQueryTree(); 172 173 if (!pnf.isClassPName()) { 174 logger.log(BasicLevel.DEBUG, "Reference from a Class to a Class"); 175 Reference ref = pnf.getReference(); 176 177 Class jormClass = null; 178 if (ref instanceof ClassRef) 179 jormClass = ((ClassRef) ref).getMOClass(); 180 else 181 throw new MedorException("Impossible to navigate with PName:" 182 + ref.getName() + " " + ref.getParent()); 183 184 ClassExtent extent = null; 185 String nodeName; 186 if (j == path.size() - 2) { 187 logger.log(BasicLevel.DEBUG, "Extent at the end of the navigation"); 189 nodeName = (op != NAVIGATION_INTO_LAST 190 ? aliasName 191 : jormClass.getFQName()); 192 pnameFieldNameIndex += 1; 193 extent = new ClassExtent( 195 jormClass, 196 nodeName, 197 PNAME_FIELD_NAME + pnameFieldNameIndex, 198 false); 199 } else { 200 logger.log(BasicLevel.DEBUG, "Extent in the middle of the navigation"); 203 nodeName = jormClass.getFQName(); 204 pnameFieldNameIndex += 1; 205 extent = new ClassExtent( 207 jormClass, 208 nodeName, 209 new String []{fieldName}, 210 true, 211 PNAME_FIELD_NAME + pnameFieldNameIndex); 212 } 213 pnf = (PNameField) extent.getField(extent.getPNameFieldName()); 215 216 JoinProject join; 217 if (!joinAlreadyConstructed) { 218 logger.log(BasicLevel.DEBUG, "Constructing new JoinProject"); 219 join = new JoinProject("", op != NAVIGATION); 220 joinAlreadyConstructed = true; 221 join.setQueryFilter( 224 new Equal( 225 new BasicFieldOperand(qtf), 226 new BasicFieldOperand(pnf) 227 ) 228 ); 229 } else { 230 join = (JoinProject) qtf.getQueryTree(); 231 logger.log(BasicLevel.DEBUG, "Re-using JoinProject " + join); 232 propagQtf = false; 233 join.setQueryFilter( 236 new And( 237 new Equal( 238 new BasicFieldOperand( 239 ((PropagatedField)qtf).getPreviousFields()[0]), 240 new BasicFieldOperand(pnf) 241 ), 242 join.getQueryFilter() 243 ) 244 ); 245 } 246 247 logger.log(BasicLevel.DEBUG, "Current qt is:"); 248 QueryTreePrinter.printQueryTree(qt, logger); 249 logger.log(BasicLevel.DEBUG, "Current join is:"); 250 QueryTreePrinter.printQueryTree(join, logger); 251 252 Field[] fToAdd = qt.getTupleStructure().getFields(); 255 logger.log(BasicLevel.DEBUG, "Adding fields:"); 256 logger.log(BasicLevel.DEBUG, "qtf is:" + qtf); 257 for (int i = 0; i < fToAdd.length; i++) { 258 if (propagQtf || qtf != fToAdd[i]) { 259 logger.log(BasicLevel.DEBUG, "\t-" + fToAdd[i].getName()); 260 try { 262 join.getField(fToAdd[i].getName()); 263 logger.log(BasicLevel.DEBUG, "Field already present: not adding."); 264 265 } catch (MedorException e) { 266 logger.log(BasicLevel.DEBUG, "Field not present: adding."); 267 268 join.addPropagatedField( 269 fToAdd[i].getName(), 270 fToAdd[i].getType(), 271 new QueryTreeField[]{(QueryTreeField) fToAdd[i]}); 272 } 273 } 274 } 277 278 fToAdd = extent.getTupleStructure().getFields(); 282 for (int i = 0; i < fToAdd.length; i++) { 283 logger.log(BasicLevel.DEBUG, "Adding propagated field " + fToAdd[i].getName()); 284 join.addPropagatedField( 285 fToAdd[i].getName(), 286 fToAdd[i].getType(), 287 new QueryTreeField[]{(QueryTreeField) fToAdd[i]}); 288 } 289 qtf = (QueryTreeField) 290 join.getField(extent.getFieldName(nodeName, fieldName)); 291 293 qt = join; 294 } else { logger.log(BasicLevel.DEBUG, "Adding the field if not already present"); 296 if (pnf.isInGenClass()) { 297 throw new MedorException( 298 "Impossible to navigate with a multi valued reference"); 299 } 300 logger.log(BasicLevel.DEBUG, "Checking that " + fieldName + " appears in " + qt); 301 String fn = contains(qt.getTupleStructure(), 303 pnf.getQueryTree().getName() + "." + fieldName); 304 if (fn != null) { 305 qtf = (QueryTreeField) qt.getTupleStructure().getField(fn); 306 } else if (qt instanceof ClassExtent) { 307 ClassExtent extent = (ClassExtent) qt; 309 TypedElement te = 310 ((Class ) extent.getMetaObject()).getTypedElement(fieldName); 311 if (te == null) 312 throw new MedorException("The jorm class " 313 + ((Class ) extent.getMetaObject()).getName() 314 + " does not provide a field " + fieldName); 315 qtf = extent.addField(te); 316 } else 317 throw new MedorException( 318 "No field " + fieldName + " found on the query tree " + qt); 319 } 320 logger.log(BasicLevel.DEBUG, "Query tree before the end of treatment:"); 321 QueryTreePrinter.printQueryTree(qt, logger); 322 qtf = endOfNavigation(op, qtf, qt, aliasName); 323 pnf = getPNameField(qtf); 324 } 325 return qtf; 326 } 327 328 329 338 private static QueryTreeField endOfNavigation(byte op, 339 QueryTreeField qtf, 340 QueryTree qt, 341 String aliasName) 342 throws MedorException { 343 PNameField pnf = getPNameField(qtf); 344 logger.log(BasicLevel.DEBUG, "Computing the end of navigation with pnf=" + pnf + " for operation " + op); 346 347 if (op != NAVIGATION && pnf != null) { 348 logger.log(BasicLevel.DEBUG, "pnf.ref=" + pnf.getReference()); 350 if (pnf.getReference() instanceof GenClassRef) { 351 353 GenClassRef gcr = (GenClassRef) pnf.getReference(); 354 String nodeName = ((Class ) gcr.getParent()).getFQName() 355 + "." + gcr.getName(); 356 pnameFieldNameIndex += 1; 357 GenClassExtent extent = new GenClassExtent( 359 gcr, 360 nodeName, 361 PNAME_FIELD_NAME + pnameFieldNameIndex, 362 GENCLASS_ELEMENT_NAME); 363 364 pnf = (PNameField) extent.getField(extent.getPNameFieldName()); 366 367 JoinProject join; 368 boolean newjoin = false; 369 if (qt instanceof JoinProject) { 370 logger.log(BasicLevel.DEBUG, "Already a join. Propagating right fields only"); 371 join = (JoinProject) qt; 372 propagateFieldsRight(extent, join, op, aliasName); 373 } else { 374 logger.log(BasicLevel.DEBUG, "Creating a join. Propagating left and right fields"); 375 join = new JoinProject("" , op != NAVIGATION); 376 propagateFieldsLeft(qt, join); 377 propagateFieldsRight(extent, join, op, aliasName); 378 newjoin = true; 379 } 380 381 try { 384 switch (op) { 385 case NAVIGATION_INTO_LAST: 386 if (newjoin) { 387 join.setQueryFilter(new Equal( 388 new BasicFieldOperand(qtf), 389 new BasicFieldOperand(pnf))); 390 } else { 391 join.setQueryFilter( 392 new And( 393 join.getQueryFilter(), 394 new Equal( 395 new BasicFieldOperand( 396 ((PropagatedField)qtf).getPreviousFields()[0]), 397 new BasicFieldOperand(pnf)) 398 ) 399 ); 400 } 401 return (QueryTreeField) join.getField((aliasName == null 402 ? extent.getElementFieldName() 403 : aliasName)); 404 case IS_NOT_EMPTY: 405 if (newjoin) { 406 join.setQueryFilter(new MemberOf( 407 Collections.singletonList(new BasicFieldOperand(qtf)), 408 Collections.singletonList(new BasicFieldOperand(pnf)))); 409 } else { 410 join.setQueryFilter( 411 new And( 412 join.getQueryFilter(), 413 new MemberOf( 414 Collections.singletonList(new BasicFieldOperand(((PropagatedField)qtf).getPreviousFields()[0])), 415 Collections.singletonList(new BasicFieldOperand(pnf)) 416 ) 417 ) 418 ); 419 } 420 return (QueryTreeField) join.getField(qtf.getName()); 421 case IS_EMPTY: 422 if (newjoin) { 423 join.setQueryFilter(new Not(new MemberOf( 424 Collections.singletonList(new BasicFieldOperand(qtf)), 425 Collections.singletonList(new BasicFieldOperand(pnf))))); 426 } else { 427 join.setQueryFilter( 428 new And( 429 join.getQueryFilter(), 430 new Not(new MemberOf( 431 Collections.singletonList(new BasicFieldOperand(((PropagatedField)qtf).getPreviousFields()[0])), 432 Collections.singletonList(new BasicFieldOperand(pnf)) 433 ) 434 ) 435 ) 436 ); 437 } 438 return (QueryTreeField) join.getField(qtf.getName()); 439 default: 440 throw new MedorException("Operation type not supported: " + op); 441 } 442 } catch (MalformedExpressionException e1) { 443 throw new MedorException(e1); 444 } 445 } else if (op == NAVIGATION_INTO_LAST 446 && pnf.getReference() instanceof ClassRef) { 447 448 ClassRef cr = (ClassRef) pnf.getReference(); 449 String nodeName = (aliasName == null 450 ? cr.getMOClass().getFQName() 451 : aliasName) + "." + cr.getName(); 452 pnameFieldNameIndex += 1; 453 ClassExtent extent = new ClassExtent( 454 cr.getMOClass(), 455 nodeName, 456 PNAME_FIELD_NAME + pnameFieldNameIndex, 457 false); 458 459 pnf = (PNameField) extent.getField(extent.getPNameFieldName()); 461 462 JoinProject join = new JoinProject("", op != NAVIGATION); 463 propagateFieldsLeft(qt, join); 464 propagateFieldsRight(extent, join, op, null); 465 join.setQueryFilter(new Equal( 466 new BasicFieldOperand(qtf), 467 new BasicFieldOperand(pnf))); 468 qtf = pnf; 469 } else { 470 throw new MedorException("Operation type (" + op 471 + ") not supported on the field: " + pnf); 472 } 473 } 474 logger.log(BasicLevel.DEBUG, "End of navigation"); 475 return qtf; 476 } 477 478 482 private static void propagateFieldsLeft(QueryTree qt, 483 QueryNode qn) throws MedorException { 484 Field[] fToAdd = qt.getTupleStructure().getFields(); 486 for (int i = 0; i < fToAdd.length; i++) { 487 logger.log(BasicLevel.DEBUG, "Propagate from left: " + fToAdd[i].getName()); 488 qn.addPropagatedField( 489 fToAdd[i].getName(), 490 fToAdd[i].getType(), 491 new QueryTreeField[]{(QueryTreeField) fToAdd[i]}); 492 } 493 } 494 495 private static void propagateFieldsRight(JormExtent extent, 496 QueryNode qn, 497 byte op, 498 String gcElemAlias) throws MedorException { 499 if (op == NAVIGATION_INTO_LAST) { 500 Field[] fToAdd = extent.getTupleStructure().getFields(); 503 String pnfn = extent.getPNameFieldName(); 504 String gcElemName = null; 505 if (gcElemAlias != null) { 506 gcElemName = ((GenClassExtent) extent).getElementFieldName(); 507 } 508 for (int i = 0; i < fToAdd.length; i++) { 510 if (!fToAdd[i].getName().equals(pnfn)) { 511 String fn = (fToAdd[i].getName().equals(gcElemName) 512 ? gcElemAlias : fToAdd[i].getName()); 513 logger.log(BasicLevel.DEBUG, "Propagate from right: " 514 + fToAdd[i].getName() + " to " + fn); 515 qn.addPropagatedField( 516 fn, 517 fToAdd[i].getType(), 518 new QueryTreeField[]{(QueryTreeField) fToAdd[i]}); 519 } 520 } 521 } 522 } 523 524 525 private static PNameField getPNameField(Field field) throws MedorException { 526 if (field instanceof PNameField) 527 return (PNameField) field; 528 else if (field instanceof PropagatedField) { 529 return getPNameField( 530 ((PropagatedField) field).getPreviousFields()[0]); 531 } else 532 return null; 533 } 534 535 private static String contains(TupleStructure ts, String fn) { 536 String res = (ts.contains(fn) ? fn : null); 537 int idx = fn.lastIndexOf(".", fn.length()); 538 while (res == null && idx != -1) { 539 res = fn.substring(idx + 1, fn.length()); 540 res = (ts.contains(res) ? res : null); 541 idx = fn.lastIndexOf(".", idx - 1); 542 } 543 return res; 544 } 545 546 public static void resetNameIndexes() { 547 pnameFieldNameIndex = 0; 548 } 549 550 public static QueryTreeField navigate_old(NavigatorOperator nav, 551 String aliasName, 552 byte op) 553 throws MedorException { 554 QueryTreeField qtf; 556 PNameField pnf; 558 559 boolean joinAlreadyConstructed = false; 560 561 String fieldName = null; 562 try { 563 fieldName = ((Operand) nav.getExpression(1)).getString(); 564 } catch (TypingException e) { 565 throw new MedorException(e); 566 } 567 Expression e = nav.getExpression(0); 568 logger.log(BasicLevel.DEBUG, "navigate(" + aliasName + ", " 569 + ExpressionPrinter.e2str(e) + ", " + fieldName 570 + ", op:" + op + ")"); 571 boolean propagQtf; 572 if (e instanceof FieldOperand) { 573 qtf = (QueryTreeField) ((FieldOperand) e).getField(); 574 pnf = getPNameField(qtf); 575 logger.log(BasicLevel.DEBUG, "Navigation from FieldOperand " + qtf.getName()); 576 propagQtf = true; 577 } else if (e instanceof NavigatorOperator) { 578 logger.log(BasicLevel.DEBUG, "Navigation from NavigatorOperator"); 579 Expression el = ((NavigatorOperator) e).getExpression(0); 580 propagQtf = el instanceof FieldOperand 581 && getPNameField(((FieldOperand) el).getField()).isClassPName(); 582 qtf = navigate((NavigatorOperator) e, null, NAVIGATION); 585 pnf = getPNameField(qtf); 586 if (qtf.getQueryTree() instanceof JoinProject) { 587 joinAlreadyConstructed = true; 588 } 589 logger.log(BasicLevel.DEBUG, "Recursive call constructed join ? " + joinAlreadyConstructed); 590 591 } else 592 throw new MedorException( 593 "Unknown left operand of the specified NavigatorOperand: " + e); 594 595 logger.log(BasicLevel.DEBUG, "propagQtf=" + propagQtf); 596 logger.log(BasicLevel.DEBUG, "qtf=" + qtf.getName() + " of node " + qtf.getQueryTree()); 597 if (pnf == null) 598 throw new MedorException("Impossible to find a PNameField"); 599 600 QueryTree qt = qtf.getQueryTree(); 602 603 if (!pnf.isClassPName()) { 604 logger.log(BasicLevel.DEBUG, "Reference from a Class to a Class"); 605 Reference ref = pnf.getReference(); 606 607 Class jormClass = null; 608 if (ref instanceof ClassRef) 609 jormClass = ((ClassRef) ref).getMOClass(); 610 else 611 throw new MedorException("Impossible to navigate with PName:" 612 + ref.getName() + " " + ref.getParent()); 613 614 ClassExtent extent = null; 615 String nodeName; 616 if (aliasName != null) { 617 nodeName = (op != NAVIGATION_INTO_LAST 619 ? aliasName 620 : jormClass.getFQName()); 621 pnameFieldNameIndex += 1; 622 extent = new ClassExtent( 624 jormClass, 625 nodeName, 626 PNAME_FIELD_NAME + pnameFieldNameIndex, 627 false); 628 } else { 629 nodeName = jormClass.getFQName(); 632 pnameFieldNameIndex += 1; 633 extent = new ClassExtent( 635 jormClass, 636 nodeName, 637 new String []{fieldName}, 638 true, 639 PNAME_FIELD_NAME + pnameFieldNameIndex); 640 } 641 pnf = (PNameField) extent.getField(extent.getPNameFieldName()); 643 644 JoinProject join; 645 join = new JoinProject("", op != NAVIGATION); 647 652 join.setQueryFilter( 655 new Equal( 656 new BasicFieldOperand(qtf), 657 new BasicFieldOperand(pnf) 658 ) 659 ); 660 661 Field[] fToAdd = qt.getTupleStructure().getFields(); 664 logger.log(BasicLevel.DEBUG, "Adding fields:"); 665 666 for (int i = 0; i < fToAdd.length; i++) { 667 if (propagQtf || qtf != fToAdd[i]) { 668 logger.log(BasicLevel.DEBUG, "\t-" + fToAdd[i].getName()); 669 join.addPropagatedField( 670 fToAdd[i].getName(), 671 fToAdd[i].getType(), 672 new QueryTreeField[]{(QueryTreeField) fToAdd[i]}); 673 } 674 } 677 678 fToAdd = extent.getTupleStructure().getFields(); 681 for (int i = 0; i < fToAdd.length; i++) { 682 logger.log(BasicLevel.DEBUG, "Adding propagated field " + fToAdd[i].getName()); 683 join.addPropagatedField( 684 fToAdd[i].getName(), 685 fToAdd[i].getType(), 686 new QueryTreeField[]{(QueryTreeField) fToAdd[i]}); 687 } 688 qtf = (QueryTreeField) 689 join.getField(extent.getFieldName(nodeName, fieldName)); 690 692 qt = join; 693 } else { 694 logger.log(BasicLevel.DEBUG, "Adding the field if not already present"); 695 if (pnf.isInGenClass()) { 696 throw new MedorException( 697 "Impossible to navigate with a multi valued reference"); 698 } 699 logger.log(BasicLevel.DEBUG, "Checking that " + fieldName + " appears in " + qt); 700 String fn = contains(qt.getTupleStructure(), 702 pnf.getQueryTree().getName() + "." + fieldName); 703 if (fn != null) { 704 qtf = (QueryTreeField) qt.getTupleStructure().getField(fn); 705 } else if (qt instanceof ClassExtent) { 706 ClassExtent extent = (ClassExtent) qt; 708 TypedElement te = 709 ((Class ) extent.getMetaObject()).getTypedElement(fieldName); 710 if (te == null) 711 throw new MedorException("The jorm class " 712 + ((Class ) extent.getMetaObject()).getName() 713 + " does not provide a field " + fieldName); 714 qtf = extent.addField(te); 715 } else 716 throw new MedorException( 717 "No field " + fieldName + " found on the query tree " + qt); 718 } 719 return endOfNavigation(op, qtf, qt, aliasName); 720 } 721 722 723 } 724 | Popular Tags |