1 10 11 package org.mmbase.bridge.implementation; 12 13 import java.util.*; 14 import org.mmbase.bridge.util.Queries; 15 import org.mmbase.cache.CachePolicy; 16 import org.mmbase.module.core.*; 17 import org.mmbase.module.corebuilders.*; 18 import org.mmbase.storage.search.*; 19 import org.mmbase.storage.search.implementation.*; 20 import org.mmbase.storage.search.implementation.database.BasicSqlHandler; 21 import org.mmbase.bridge.*; 22 import org.mmbase.util.logging.*; 23 import org.mmbase.security.Authorization; 24 25 36 public class BasicQuery implements Query { 37 38 private static final Logger log = Logging.getLoggerInstance(BasicQuery.class); 39 40 43 protected boolean used = false; 44 45 49 protected boolean aggregating = false; 51 54 protected CachePolicy cachePolicy = CachePolicy.ALWAYS; 55 56 59 protected Authorization.QueryCheck queryCheck = null; 60 61 66 protected Constraint insecureConstraint = null; 67 68 69 private HashMap aliasSequences = new HashMap(); 72 73 76 protected BasicSearchQuery query; 77 78 81 protected Cloud cloud; 82 83 84 88 protected List implicitFields = new ArrayList(); 89 90 93 protected List explicitFields = new ArrayList(); 94 95 BasicQuery(Cloud c) { 96 query = new BasicSearchQuery(); 97 cloud = c; 98 } 99 100 BasicQuery(Cloud c, boolean aggregating) { 101 query = new BasicSearchQuery(aggregating); 102 this.aggregating = aggregating; 103 cloud = c; 104 } 105 106 public BasicQuery(Cloud c, BasicSearchQuery q) { query = q; 108 cloud = c; 109 this.aggregating = q.isAggregating(); 110 } 111 112 113 public BasicSearchQuery getQuery() { 114 return query; 115 } 116 117 protected void createNewQuery() { 118 query = new BasicSearchQuery(); 119 } 120 121 122 124 public List getSteps() { 125 return query.getSteps(); 126 } 127 public List getFields() { 128 return query.getFields(); 129 } 130 public Constraint getConstraint() { 131 return query.getConstraint(); 132 } 133 134 public Constraint getCleanConstraint() { 136 if (queryCheck != null) { 137 return insecureConstraint; 138 } else { 139 return query.getConstraint(); 140 } 141 } 142 143 public int getMaxNumber() { 145 return query.getMaxNumber(); 146 } 147 public int getOffset() { 148 return query.getOffset(); 149 } 150 public List getSortOrders() { 151 return query.getSortOrders(); 152 } 153 public boolean isDistinct() { 154 return query.isDistinct(); 155 } 156 157 159 public boolean isAggregating() { 160 return aggregating; 161 } 162 163 public CachePolicy getCachePolicy() { 164 return cachePolicy; 165 } 166 167 public void setCachePolicy(CachePolicy policy) { 168 this.cachePolicy = policy; 169 } 170 171 174 protected void removeSecurityConstraintFromClone(BasicSearchQuery clone) { 175 if (log.isDebugEnabled()) { 176 log.debug("Removing " + queryCheck + " FROM " + clone); 177 } 178 if (queryCheck != null) { 179 Constraint secureConstraint = queryCheck.getConstraint(); 180 if (secureConstraint != null) { 181 Constraint constraint = clone.getConstraint(); 182 if (secureConstraint.equals(constraint)) { 184 clone.setConstraint(null); 185 } else { BasicCompositeConstraint compConstraint = (BasicCompositeConstraint) constraint; 187 compConstraint.removeChild(secureConstraint); if (compConstraint.getChilds().size() == 0) { clone.setConstraint(null); 190 } 191 if (compConstraint.getChilds().size() == 1) { Constraint newConstraint = (Constraint) compConstraint.getChilds().get(0); 193 clone.setConstraint(newConstraint); 194 } 195 } 196 } 197 } 198 199 } 200 201 public Object clone() { try { 203 BasicQuery clone = (BasicQuery) super.clone(); 204 clone.query = (BasicSearchQuery) query.clone(); 205 clone.aliasSequences = (HashMap) aliasSequences.clone(); 206 removeSecurityConstraintFromClone(clone.query); 207 clone.insecureConstraint = null; 208 clone.queryCheck = null; 209 clone.used = false; 210 return clone; 211 } catch (CloneNotSupportedException e) { 212 throw new InternalError (e.toString()); 214 } 215 } 216 public Query aggregatingClone() { 217 BasicSearchQuery bsq = new BasicSearchQuery(query, BasicSearchQuery.COPY_AGGREGATING); 218 removeSecurityConstraintFromClone(bsq); 219 BasicQuery clone = new BasicQuery(cloud, bsq); 220 clone.used = false; 221 clone.aggregating = true; 222 return clone; 223 } 224 225 public Query cloneWithoutFields() { 226 BasicSearchQuery bsq = new BasicSearchQuery(query, BasicSearchQuery.COPY_WITHOUTFIELDS); 227 removeSecurityConstraintFromClone(bsq); 228 BasicQuery clone = new BasicQuery(cloud, bsq); 229 clone.used = false; 230 clone.aggregating = false; 231 return clone; 232 } 233 234 237 protected String createAlias(String name) { 238 if (used) throw new BridgeException("Query was used already"); 239 Integer seq = (Integer ) aliasSequences.get(name); 240 if (seq == null) { 241 seq = new Integer (0); 242 } else { 243 seq = new Integer (seq.intValue() + 1); 244 } 245 aliasSequences.put(name, seq); 246 return glueAlias(name, seq); 247 } 248 249 252 protected String glueAlias(String aliasBase, Integer seq) { 253 if (seq == null) return aliasBase; 254 int s = seq.intValue(); 255 if (s == 0) { 256 return aliasBase; 257 } else { 258 return aliasBase + s; 259 } 260 } 261 262 263 public Step addStep(NodeManager nm) { 264 if (used) throw new BridgeException("Query was used already"); 265 266 removeSecurityConstraint(); MMObjectBuilder builder = MMBase.getMMBase().getBuilder(nm.getName()); 268 if (builder == null) throw new BridgeException("No builder with name " + nm.getName() + " (perhaps " + nm + " is virtual?)"); 269 BasicStep step = query.addStep(builder); 270 setAlias(step, ""); if (! aggregating) { 272 addFieldImplicit(step, nm.getField("number")); 273 } 274 275 return step; 276 } 277 278 public void setAlias(Step step, String alias) { 279 String currentAlias = step.getAlias(); 280 String aliasBase = step.getTableName(); 281 282 285 Integer currentSeq = (Integer ) aliasSequences.get(aliasBase); 286 if (currentSeq != null && glueAlias(aliasBase, currentSeq).equals(currentAlias)) { 287 if (currentSeq.intValue() == 0) { 288 aliasSequences.put(aliasBase, null); 289 } else { 290 aliasSequences.put(aliasBase, new Integer (currentSeq.intValue() - 1)); 291 } 292 } 293 if ("".equals(alias)) { 294 alias = createAlias(aliasBase); 295 } 296 297 BasicStep basicStep = (BasicStep) step; 298 basicStep.setAlias(alias); 299 } 300 301 protected BasicRelationStep addRelationStep(InsRel insrel, NodeManager otherNodeManager, int direction) { 302 MMObjectBuilder otherBuilder = ((BasicNodeManager) otherNodeManager).builder; 303 BasicRelationStep relationStep = query.addRelationStep(insrel, otherBuilder); 304 relationStep.setDirectionality(direction); 305 relationStep.setAlias(createAlias(relationStep.getTableName())); 306 NodeManager relationManager = otherNodeManager.getCloud().getNodeManager(relationStep.getTableName()); 307 BasicStep next = (BasicStep) relationStep.getNext(); 308 next.setAlias(createAlias(next.getTableName())); 309 if (! aggregating) { 310 addFieldImplicit(relationStep, relationManager.getField("number")); addFieldImplicit(next, otherNodeManager.getField("number")); } 315 return relationStep; 316 } 317 public RelationStep addRelationStep(NodeManager otherNodeManager) { 318 return addRelationStep(otherNodeManager, null, "BOTH"); 319 } 320 321 322 public RelationStep addRelationStep(NodeManager otherNodeManager, String role, String direction) { 323 if ("".equals(role)) role = null; 324 return addRelationStep(otherNodeManager, role, direction, true); 325 } 326 327 328 protected RelationStep addRelationStep(NodeManager otherNodeManager, String role, String direction, boolean warnOnImpossibleStep) { 329 if (used) throw new BridgeException("Query was used already"); 330 331 int relationDir = Queries.getRelationStepDirection(direction); 333 334 TypeRel typeRel = BasicCloudContext.mmb.getTypeRel(); 335 if (role == null) { 336 InsRel insrel = BasicCloudContext.mmb.getInsRel(); 337 BasicRelationStep step = addRelationStep(insrel, otherNodeManager, relationDir); 338 if (!typeRel.optimizeRelationStep(step, cloud.getNodeManager(step.getPrevious().getTableName()).getNumber(), otherNodeManager.getNumber(), -1, relationDir)) { 339 if (relationDir != RelationStep.DIRECTIONS_SOURCE && 340 relationDir != RelationStep.DIRECTIONS_DESTINATION && 341 warnOnImpossibleStep) { 342 log.warn("Added an impossible relation step (" + step + " to " + otherNodeManager + ") to the query. The query-result will always be empty now (so you could as well not execute it)."); 343 log.warn(Logging.applicationStacktrace()); 344 } 345 } 346 return step; 347 } else { 348 RelDef relDef = BasicCloudContext.mmb.getRelDef(); 349 int r = relDef.getNumberByName(role); 350 if (r == -1) { 351 throw new NotFoundException("Role '" + role + "' does not exist."); 352 } 353 MMObjectNode relDefNode = relDef.getNode(r); 354 InsRel insrel = ((RelDef)relDefNode.getBuilder()).getBuilder(relDefNode.getNumber()); 355 BasicRelationStep step = addRelationStep(insrel, otherNodeManager, relationDir); 356 step.setRole(new Integer (r)); 357 if (! cloud.hasNodeManager(role)) { 358 step.setAlias(createAlias(role)); 359 } 360 if (! typeRel.optimizeRelationStep(step, cloud.getNodeManager(step.getPrevious().getTableName()).getNumber(), otherNodeManager.getNumber(), r, relationDir)) { 361 if (relationDir != RelationStep.DIRECTIONS_SOURCE && 362 relationDir != RelationStep.DIRECTIONS_DESTINATION && 363 warnOnImpossibleStep) { 364 log.warn("Added an impossible relation step (" + step + " to " + otherNodeManager + ") to the query. The query-result will always be empty now (so you could as well not execute it). "); 366 log.warn(Logging.applicationStacktrace()); 367 } 368 } 369 return step; 370 } 371 } 372 373 public void removeFields() { 374 query.removeFields(); 375 explicitFields.clear(); 376 Iterator i = implicitFields.iterator(); 377 while (i.hasNext()) { 378 BasicStepField sf = (BasicStepField) i.next(); 379 Step addedStep = sf.getStep(); 380 query.addField(addedStep, sf.getField()); 381 } 382 383 } 384 385 386 public StepField addField(Step step, Field field) { 387 if (used) throw new BridgeException("Query was used already"); 388 BasicStepField sf = new BasicStepField(step, ((BasicField)field).coreField); if (! implicitFields.remove(sf)) {; sf = query.addField(step, ((BasicField)field).coreField); } 392 explicitFields.add(sf); 393 return sf; 394 } 395 public StepField addField(String fieldIdentifier) { 396 if (used) throw new BridgeException("Query was used already"); 398 int dot = fieldIdentifier.indexOf('.'); 399 if (dot <= 0) throw new BridgeException("No step alias found in field identifier '" + fieldIdentifier + "'. Expected a dot in it."); 400 String stepAlias = fieldIdentifier.substring(0, dot); 401 String fieldName = fieldIdentifier.substring(dot + 1); 402 Step step = getStep(stepAlias); 403 if (step == null) throw new NotFoundException("No step with alias '" + stepAlias + "' found in " + getSteps()); 404 NodeManager nm = cloud.getNodeManager(step.getTableName()); 405 Field field = nm.getField(fieldName); 406 return addField(step, field); 407 } 408 409 412 protected void addFieldImplicit(Step step, Field field) { 413 if (used) throw new BridgeException("Query was used already"); 414 if (! query.isDistinct()) { 415 org.mmbase.core.CoreField coreField = ((BasicField)field).coreField; StepField sf = query.addFieldUnlessPresent(step, coreField); 417 if (! implicitFields.contains(sf)) { 418 implicitFields.add(sf); 419 } 420 } 421 } 422 423 public StepField createStepField(Step step, Field field) { 424 if (field == null) throw new BridgeException("Field is null"); 425 return 426 new BasicStepField(step, ((BasicField)field).coreField); } 428 429 public StepField createStepField(Step step, String fieldName) { 430 return createStepField(step, cloud.getNodeManager(step.getTableName()).getField(fieldName)); 431 } 432 433 434 435 public Step getStep(String stepAlias) { 436 return Queries.searchStep(getSteps(), stepAlias); 437 } 438 439 public StepField createStepField(String fieldIdentifier) { 440 int dot = fieldIdentifier.indexOf('.'); 442 if (dot <= 0) throw new BridgeException("No step alias found in field identifier '" + fieldIdentifier + "'. Expected a dot in it."); 443 String stepAlias = fieldIdentifier.substring(0, dot); 444 String fieldName = fieldIdentifier.substring(dot + 1); 445 Step step = getStep(stepAlias); 446 if (step == null) throw new NotFoundException("No step with alias '" + stepAlias + "' found in " + getSteps()); 447 NodeManager nm = cloud.getNodeManager(step.getTableName()); 448 Field field = nm.getField(fieldName); 449 return createStepField(step, field); 450 } 451 452 public AggregatedField addAggregatedField(Step step, Field field, int aggregationType) { 453 if (used) throw new BridgeException("Query was used already"); 454 BasicAggregatedField aggregatedField = query.addAggregatedField(step, ((BasicField)field).coreField, aggregationType); 457 if (this instanceof NodeQuery) { NodeQuery nodeQuery = (NodeQuery) this; 459 ((BasicStep) step).setAlias(nodeQuery.getNodeManager().getName()); 460 } 463 464 466 return aggregatedField; 467 } 468 469 470 471 public Query setDistinct(boolean distinct) { 472 if (used) throw new BridgeException("Query was used already"); 473 query.setDistinct(distinct); 474 if (distinct) { query.removeFields(); 476 implicitFields.clear(); 477 Iterator i = explicitFields.iterator(); 478 while (i.hasNext()) { 479 BasicStepField sf = (BasicStepField) i.next(); 480 query.addField(sf.getStep(), sf.getField()); 481 } 482 } 483 return this; 484 } 485 486 public Query setMaxNumber(int maxNumber) { 487 if (used) throw new BridgeException("Query was used already"); 488 query.setMaxNumber(maxNumber); 489 return this; 490 } 491 public Query setOffset(int offset) { 492 if (used) throw new BridgeException("Query was used already"); 493 query.setOffset(offset); 494 return this; 495 496 } 497 498 public LegacyConstraint createConstraint(String s) { 499 return new BasicLegacyConstraint(s); 500 } 501 502 public FieldNullConstraint createConstraint(StepField f) { 503 return new BasicFieldNullConstraint(f); 504 } 505 506 public FieldValueConstraint createConstraint(StepField f, Object v) { 507 return createConstraint(f, FieldCompareConstraint.EQUAL, v); 508 } 509 510 public FieldValueConstraint createConstraint(StepField f, int op, Object v, int part) { 511 BasicFieldValueConstraint c = new BasicFieldValueDateConstraint(f, v, part); 512 c.setOperator(op); 513 return c; 514 } 515 516 public FieldValueConstraint createConstraint(StepField f, int op, Object v) { 517 if (v instanceof Node) v = new Integer (((Node)v).getNumber()); 518 BasicFieldValueConstraint c = new BasicFieldValueConstraint(f, v); 519 c.setOperator(op); 520 return c; 521 } 522 523 public CompareFieldsConstraint createConstraint(StepField f, int op, StepField v) { 524 BasicCompareFieldsConstraint c = new BasicCompareFieldsConstraint(f, v); 525 c.setOperator(op); 526 return c; 527 } 528 529 public FieldValueBetweenConstraint createConstraint(StepField f, Object o1, Object o2) { 530 return new BasicFieldValueBetweenConstraint(f, o1, o2); 531 } 532 533 public FieldValueInConstraint createConstraint(StepField f, SortedSet v) { 534 if (v.size() == 0) { Step step = f.getStep(); 536 StepField nf = createStepField(step, "number"); 537 BasicFieldValueInConstraint c = new BasicFieldValueInConstraint(nf); 538 c.addValue(new Integer (-1)); 539 return c; 540 } else { 541 BasicFieldValueInConstraint c = new BasicFieldValueInConstraint(f); 542 Iterator i = v.iterator(); 543 while (i.hasNext()) { 544 c.addValue(i.next()); 545 } 546 return c; 547 } 548 } 549 550 public Constraint setInverse(Constraint c, boolean i) { 551 ((BasicConstraint) c).setInverse(i); 552 return c; 553 } 554 555 public FieldConstraint setCaseSensitive(FieldConstraint c, boolean s) { 556 ((BasicFieldConstraint) c).setCaseSensitive(s); 557 return c; 558 559 } 560 public CompositeConstraint createConstraint(Constraint c1, int operator, Constraint c2) { 561 if ((!used) && c1 instanceof BasicCompositeConstraint && ((CompositeConstraint) c1).getLogicalOperator() == operator) { 562 if (c2 != null) ((BasicCompositeConstraint) c1).addChild(c2); 563 return (CompositeConstraint) c1; 564 } else { 565 BasicCompositeConstraint c = new BasicCompositeConstraint(operator); 566 if (c1 != null) c.addChild(c1); 567 if (c2 != null) c.addChild(c2); 568 return c; 569 } 570 } 571 572 public void setConstraint(Constraint c) { 573 if (used) throw new BridgeException("Query was used already"); 574 query.setConstraint(c); 575 } 576 577 578 public SortOrder addSortOrder(StepField f, int direction) { 579 return addSortOrder(f, direction, false); 580 } 581 public SortOrder addSortOrder(StepField f, int direction, boolean caseSensitive) { 582 if (used) throw new BridgeException("Query was used already"); 583 if (f == null) throw new BridgeException("Cannot add sortorder on 'null' step field"); 584 BasicSortOrder s = query.addSortOrder(f); 585 s.setDirection(direction); 586 s.setCaseSensitive(caseSensitive); 587 return s; 588 } 589 590 593 public void addNode(Step s, int nodeNumber) { 594 if (used) throw new BridgeException("Query was used already"); 595 BasicStep step = (BasicStep) s; 596 step.addNode(nodeNumber); 597 return; 598 } 599 600 public void addNode(Step s, Node node) { 601 addNode(s, node.getNumber()); 602 } 603 604 public boolean isUsed() { 605 return used; 606 } 607 608 public boolean markUsed() { 609 boolean wasUsed = used; 610 if (queryCheck == null) { } 615 used = true; 616 return wasUsed; 617 } 618 619 620 boolean isSecure() { 621 return queryCheck != null && queryCheck.isChecked(); 622 } 623 624 629 void setSecurityConstraint(Authorization.QueryCheck c) { 630 if (queryCheck != null) { 631 throw new BridgeException("Already a security constraints set"); 632 } 633 if (insecureConstraint != null) { 634 throw new BridgeException("Already a insecure constraint defined"); 635 } 636 if (c == null) { 637 throw new BridgeException("QueryCheck may not be null"); 638 } 639 if (log.isDebugEnabled()) { 640 log.debug("Setting security check " + c + " TO " + this); 641 } 642 queryCheck = c; 643 644 insecureConstraint = query.getConstraint(); Constraint secureConstraint = queryCheck.getConstraint(); 646 if (secureConstraint != null) { 647 if (insecureConstraint != null) { 648 BasicCompositeConstraint compConstraint = new BasicCompositeConstraint(CompositeConstraint.LOGICAL_AND); 649 compConstraint.addChild(insecureConstraint); 650 compConstraint.addChild(secureConstraint); 651 query.setConstraint(compConstraint); 652 } else { 653 query.setConstraint(secureConstraint); 654 } 655 } 656 } 657 658 662 void removeSecurityConstraint() { 663 if (log.isDebugEnabled()) { 664 log.debug("Removing " + queryCheck + " FROM " + this); 665 } 666 if (queryCheck != null) { 667 query.setConstraint(insecureConstraint); 668 insecureConstraint = null; 669 } 670 queryCheck = null; 671 672 } 673 674 public Cloud getCloud() { 675 return cloud; 676 } 677 678 public NodeList getList() { 679 return cloud.getList(this); 680 } 681 682 public boolean equals(Object obj) { 683 return query.equals(obj); 684 } 685 686 public int hashCode() { 688 return query.hashCode(); 689 } 690 691 692 public String toString() { 693 return query.toString() + (used ? "(used)" : "") + "INSECURE: " + insecureConstraint + " QUERYCHECK: " + queryCheck; 694 695 } 696 private static final BasicSqlHandler sqlHandler = new BasicSqlHandler(); 697 public String toSql() { 698 try { 699 return sqlHandler.toSql(this, sqlHandler); 700 } catch (org.mmbase.storage.search.SearchQueryException sqe) { 701 return sqe.getMessage() + ": " + toString(); 702 } catch (Exception ise) { 703 return ise.getMessage() + ": " + toString(); 704 } 705 706 } 707 708 709 710 } 711 | Popular Tags |