1 10 package org.mmbase.storage.search.implementation; 11 12 import java.util.*; 13 import org.mmbase.module.core.MMObjectBuilder; 14 import org.mmbase.module.core.MMBase; 15 import org.mmbase.module.corebuilders.*; 16 import org.mmbase.core.CoreField; 17 import org.mmbase.storage.search.*; 18 import org.mmbase.util.logging.*; 19 20 27 public class BasicSearchQuery implements SearchQuery, Cloneable { 28 private static final Logger log = Logging.getLoggerInstance(BasicSearchQuery.class); 29 30 31 private boolean distinct = false; 32 33 34 private int maxNumber = SearchQuery.DEFAULT_MAX_NUMBER; 35 36 37 private int offset = SearchQuery.DEFAULT_OFFSET; 38 39 40 private List steps = new ArrayList(); 41 42 43 protected List fields = new ArrayList(); 44 45 46 private List sortOrders = new ArrayList(); 47 48 49 private Constraint constraint = null; 50 51 52 private boolean aggregating = false; 53 54 55 private boolean hasChangedHashcode = true; 56 private int savedHashcode = -1; 57 58 63 public BasicSearchQuery(boolean aggregating) { 64 this.aggregating = aggregating; 65 hasChangedHashcode = true; 66 } 67 68 71 public BasicSearchQuery() { 72 this(false); 73 } 74 75 76 public final static int COPY_NORMAL = 0; 77 public final static int COPY_AGGREGATING = 1; 78 public final static int COPY_WITHOUTFIELDS = 2; 79 80 83 84 public BasicSearchQuery(SearchQuery q, int copyMethod) { 85 distinct = q.isDistinct(); 86 copySteps(q); 87 Constraint c = q.getConstraint(); 88 if (c != null) { 89 setConstraint(copyConstraint(q, c)); 90 } 91 switch(copyMethod) { 92 case COPY_NORMAL: 93 copyFields(q); 94 case COPY_WITHOUTFIELDS: 95 copySortOrders(q); 96 maxNumber = q.getMaxNumber(); 97 offset = q.getOffset(); 98 aggregating = false; 99 break; 100 case COPY_AGGREGATING: 101 aggregating = true; 102 break; 103 default: 104 log.debug("Unknown copy method " + copyMethod); 105 break; 106 } 107 hasChangedHashcode = true; 108 } 109 110 111 116 public BasicSearchQuery(SearchQuery q) { 117 this(q, COPY_NORMAL); 118 } 119 120 121 public Object clone() { 122 try { 123 BasicSearchQuery clone = (BasicSearchQuery) super.clone(); 124 clone.copySteps(this); 125 clone.copyFields(this); 126 clone.copySortOrders(this); 127 Constraint c = getConstraint(); 128 if (c != null) { 129 clone.setConstraint(copyConstraint(this, c)); 130 } 131 return clone; 132 } catch (CloneNotSupportedException e) { 133 throw new InternalError (e.toString()); 135 } 136 } 137 138 139 protected void copySteps(SearchQuery q) { 140 MMBase mmb = MMBase.getMMBase(); 141 steps = new ArrayList(); 142 Iterator i = q.getSteps().iterator(); 143 while (i.hasNext()) { 144 Step step = (Step) i.next(); 145 if (step instanceof RelationStep) { 146 RelationStep relationStep = (RelationStep) step; 147 MMObjectBuilder dest = mmb.getBuilder(relationStep.getNext().getTableName()); 148 InsRel insrel = (InsRel) mmb.getBuilder(relationStep.getTableName()); 149 BasicRelationStep newRelationStep = addRelationStep(insrel, dest); 150 newRelationStep.setDirectionality(relationStep.getDirectionality()); 151 newRelationStep.setCheckedDirectionality(relationStep.getCheckedDirectionality()); 152 newRelationStep.setRole(relationStep.getRole()); 153 newRelationStep.setAlias(relationStep.getAlias()); 154 Iterator j = relationStep.getNodes().iterator(); 155 while (j.hasNext()) { 156 newRelationStep.addNode(((Integer ) j.next()).intValue()); 157 } 158 BasicStep next = (BasicStep) relationStep.getNext(); 159 BasicStep newNext = (BasicStep) newRelationStep.getNext(); 160 newNext.setAlias(next.getAlias()); 161 j = next.getNodes().iterator(); 162 while (j.hasNext()) { 163 newNext.addNode(((Integer ) j.next()).intValue()); 164 } 165 i.next(); 167 } else { 168 BasicStep newStep = addStep(mmb.getBuilder(step.getTableName())); 169 newStep.setAlias(step.getAlias()); 170 Iterator j = step.getNodes().iterator(); 171 while (j.hasNext()) { 172 newStep.addNode(((Integer ) j.next()).intValue()); 173 } 174 } 175 } 176 hasChangedHashcode = true; 178 } 179 protected void copyFields(SearchQuery q) { 180 fields = new ArrayList(); 181 MMBase mmb = MMBase.getMMBase(); 182 Iterator i = q.getFields().iterator(); 183 while (i.hasNext()) { 184 StepField field = (StepField) i.next(); 185 Step step = field.getStep(); 186 MMObjectBuilder bul = mmb.getBuilder(step.getTableName()); 187 int j = q.getSteps().indexOf(step); 188 if (j == -1) { 189 throw new RuntimeException ("Step " + step + " could not be found in " + q.getSteps()); 190 } 191 Step newStep = (Step) steps.get(j); 192 BasicStepField newField = addField(newStep, bul.getField(field.getFieldName())); 193 newField.setAlias(field.getAlias()); 194 } 195 hasChangedHashcode = true; 196 } 198 protected void copySortOrders(SearchQuery q) { 199 sortOrders = new ArrayList(); 200 MMBase mmb = MMBase.getMMBase(); 201 Iterator i = q.getSortOrders().iterator(); 202 while (i.hasNext()) { 203 SortOrder sortOrder = (SortOrder) i.next(); 204 StepField field = sortOrder.getField(); 205 int j = q.getFields().indexOf(field); 206 StepField newField; 207 if (j == -1 || j >= fields.size()) { Step step = field.getStep(); 209 MMObjectBuilder bul = mmb.getBuilder(step.getTableName()); 210 newField = new BasicStepField(field.getStep(), bul.getField(field.getFieldName())); 211 } else { 212 newField = (StepField) fields.get(j); 213 } 214 BasicSortOrder newSortOrder = addSortOrder(newField); 215 newSortOrder.setDirection(sortOrder.getDirection()); 216 } 217 hasChangedHashcode = true; 218 } 219 220 223 protected static StepField createNewStepField(SearchQuery q, StepField f) { 224 Step fstep = f.getStep(); 225 List steps = q.getSteps(); 227 Step step = (Step) steps.get(steps.indexOf(fstep)); 228 MMObjectBuilder bul = MMBase.getMMBase().getBuilder(step.getTableName()); 229 return new BasicStepField(step, bul.getField(f.getFieldName())); 230 } 231 232 233 236 protected static Constraint copyConstraint(SearchQuery q, Constraint c) { 237 if (c instanceof CompositeConstraint) { 238 CompositeConstraint constraint = (CompositeConstraint) c; 239 BasicCompositeConstraint newConstraint = new BasicCompositeConstraint(constraint.getLogicalOperator()); 240 Iterator i = constraint.getChilds().iterator(); 241 while (i.hasNext()) { 242 Constraint cons = (Constraint) i.next(); 243 newConstraint.addChild(copyConstraint(q, cons)); 244 } 245 newConstraint.setInverse(constraint.isInverse()); 246 return newConstraint; 247 } else if (c instanceof CompareFieldsConstraint) { 248 CompareFieldsConstraint constraint = (CompareFieldsConstraint) c; 249 BasicCompareFieldsConstraint newConstraint = new BasicCompareFieldsConstraint(createNewStepField(q, constraint.getField()), createNewStepField(q, constraint.getField2())); 250 newConstraint.setOperator(constraint.getOperator()); 251 newConstraint.setInverse(constraint.isInverse()); 252 newConstraint.setCaseSensitive(constraint.isCaseSensitive()); 253 return newConstraint; 254 } else if (c instanceof FieldValueDateConstraint) { 255 FieldValueDateConstraint constraint = (FieldValueDateConstraint) c; 256 Object value = constraint.getValue(); 257 BasicFieldValueDateConstraint newConstraint = new BasicFieldValueDateConstraint(createNewStepField(q, constraint.getField()), value, constraint.getPart()); 258 newConstraint.setOperator(constraint.getOperator()); 259 newConstraint.setInverse(constraint.isInverse()); 260 newConstraint.setCaseSensitive(constraint.isCaseSensitive()); 261 return newConstraint; 262 } else if (c instanceof FieldValueConstraint) { 263 FieldValueConstraint constraint = (FieldValueConstraint) c; 264 Object value = constraint.getValue(); 265 BasicFieldValueConstraint newConstraint = new BasicFieldValueConstraint(createNewStepField(q, constraint.getField()), value); 266 newConstraint.setOperator(constraint.getOperator()); 267 newConstraint.setInverse(constraint.isInverse()); 268 newConstraint.setCaseSensitive(constraint.isCaseSensitive()); 269 return newConstraint; 270 } else if (c instanceof FieldNullConstraint) { 271 FieldNullConstraint constraint = (FieldNullConstraint) c; 272 BasicFieldNullConstraint newConstraint = new BasicFieldNullConstraint(createNewStepField(q, constraint.getField())); 273 newConstraint.setInverse(constraint.isInverse()); 274 newConstraint.setCaseSensitive(constraint.isCaseSensitive()); 275 return newConstraint; 276 } else if (c instanceof FieldValueBetweenConstraint) { 277 FieldValueBetweenConstraint constraint = (FieldValueBetweenConstraint) c; 278 BasicFieldValueBetweenConstraint newConstraint; 279 try { 280 newConstraint = new BasicFieldValueBetweenConstraint(createNewStepField(q, constraint.getField()), constraint.getLowerLimit(), constraint.getUpperLimit()); 281 } catch (NumberFormatException e) { 282 newConstraint = new BasicFieldValueBetweenConstraint(createNewStepField(q, constraint.getField()), constraint.getLowerLimit(), constraint.getUpperLimit()); 283 } 284 newConstraint.setInverse(constraint.isInverse()); 285 newConstraint.setCaseSensitive(constraint.isCaseSensitive()); 286 return newConstraint; 287 } else if (c instanceof FieldValueInConstraint) { 288 FieldValueInConstraint constraint = (FieldValueInConstraint) c; 289 BasicFieldValueInConstraint newConstraint = new BasicFieldValueInConstraint(createNewStepField(q, constraint.getField())); 290 291 Iterator k = constraint.getValues().iterator(); 292 while (k.hasNext()) { 293 Object value = k.next(); 294 newConstraint.addValue(value); 295 } 296 newConstraint.setInverse(constraint.isInverse()); 297 newConstraint.setCaseSensitive(constraint.isCaseSensitive()); 298 return newConstraint; 299 } else if (c instanceof LegacyConstraint) { 300 LegacyConstraint constraint = (LegacyConstraint) c; 301 BasicLegacyConstraint newConstraint = new BasicLegacyConstraint(constraint.getConstraint()); 302 return newConstraint; 303 } 304 throw new RuntimeException ("Could not copy constraint " + c); 305 } 306 307 313 public BasicSearchQuery setDistinct(boolean distinct) { 314 this.distinct = distinct; 315 hasChangedHashcode = true; 316 return this; 317 } 318 319 326 public BasicSearchQuery setMaxNumber(int maxNumber) { 327 if (maxNumber < -1) { 328 throw new IllegalArgumentException ( "Invalid maxNumber value: " + maxNumber); 329 } 330 this.maxNumber = maxNumber; 331 hasChangedHashcode = true; 332 return this; 333 } 334 335 342 public BasicSearchQuery setOffset(int offset) { 343 if (offset < 0) { 344 throw new IllegalArgumentException ( 345 "Invalid offset value: " + offset); 346 } 347 this.offset = offset; 348 hasChangedHashcode = true; 349 return this; 350 } 351 352 359 public BasicStep addStep(MMObjectBuilder builder) { 360 BasicStep step = new BasicStep(builder); 361 steps.add(step); 362 hasChangedHashcode = true; 363 return step; 364 } 365 366 378 public BasicRelationStep addRelationStep(InsRel builder, MMObjectBuilder nextBuilder) { 379 int nrOfSteps = steps.size(); 380 if (nrOfSteps == 0) { 381 throw new IllegalStateException ("No previous step."); 382 } 383 BasicStep previous = (BasicStep) steps.get(nrOfSteps - 1); 384 BasicStep next = new BasicStep(nextBuilder); 385 BasicRelationStep relationStep = new BasicRelationStep(builder, previous, next); 386 steps.add(relationStep); 387 steps.add(next); 388 hasChangedHashcode = true; 389 return relationStep; 390 } 391 392 402 public BasicStepField addField(Step step, CoreField fieldDefs) { 403 if (aggregating) { 404 throw new UnsupportedOperationException ("Adding non-aggregated field to aggregating query."); 405 } 406 BasicStepField field = new BasicStepField(step, fieldDefs); 407 assert ! fields.contains(field); 408 fields.add(field); 409 hasChangedHashcode = true; 410 return field; 411 } 412 413 416 public BasicStepField addFieldUnlessPresent(Step step, CoreField fieldDefs) { 417 if (aggregating) { 418 throw new UnsupportedOperationException ("Adding non-aggregated field to aggregating query."); 419 } 420 BasicStepField field = new BasicStepField(step, fieldDefs); 421 int i = fields.indexOf(field); 422 if (i == -1) { 423 fields.add(field); 424 hasChangedHashcode = true; 425 } else { 426 field = (BasicStepField) fields.get(i); 427 } 428 return field; 429 } 430 431 protected void mapField(CoreField field, StepField stepField) { 433 434 } 435 436 440 public void addFields(Step step) { 441 MMBase mmb = MMBase.getMMBase(); 442 MMObjectBuilder builder = mmb.getBuilder(step.getTableName()); 443 Iterator iFields = builder.getFields().iterator(); 444 while (iFields.hasNext()) { 445 CoreField field = (CoreField) iFields.next(); 446 if (field.inStorage()) { 447 BasicStepField stepField = addField(step, field); 448 mapField(field, stepField); 449 } 450 } 451 hasChangedHashcode = true; 452 } 453 454 public void removeFields() { 455 fields.clear(); 456 hasChangedHashcode = true; 457 } 458 459 470 public BasicAggregatedField addAggregatedField(Step step, CoreField field, int aggregationType) { 471 if (!aggregating) { 472 throw new UnsupportedOperationException ( 473 "Adding aggregated field to non-aggregating query."); 474 } 475 BasicAggregatedField stepField = new BasicAggregatedField(step, field, aggregationType); 476 fields.add(stepField); 477 hasChangedHashcode = true; 478 return stepField; 479 } 480 481 488 public BasicSortOrder addSortOrder(StepField field) { 489 BasicSortOrder sortOrder = new BasicSortOrder(field); 490 sortOrders.add(sortOrder); 491 hasChangedHashcode = true; 492 return sortOrder; 493 } 494 495 501 public void setConstraint(Constraint constraint) { 502 this.constraint = constraint; 503 hasChangedHashcode = true; 504 } 505 506 public boolean isDistinct() { 508 return distinct; 509 } 510 511 public boolean isAggregating() { 513 return aggregating; 514 } 515 516 public List getSortOrders() { 518 return Collections.unmodifiableList(sortOrders); 520 } 521 522 public List getSteps() { 524 return Collections.unmodifiableList(steps); 526 } 527 528 529 public List getFields() { 531 return Collections.unmodifiableList(fields); 533 } 534 535 public Constraint getConstraint() { 537 return constraint; 538 } 539 540 public int getMaxNumber() { 542 return maxNumber; 543 } 544 545 public int getOffset() { 547 return offset; 548 } 549 550 public boolean equals(Object obj) { 552 if (obj == this) { 553 return true; 554 } 555 if (obj instanceof SearchQuery) { 556 SearchQuery query = (SearchQuery) obj; 557 return distinct == query.isDistinct() 558 && maxNumber == query.getMaxNumber() 559 && offset == query.getOffset() 560 && steps.equals(query.getSteps()) 561 && fields.equals(query.getFields()) 562 && sortOrders.equals(query.getSortOrders()) 563 && (constraint == null? 564 query.getConstraint() == null: 565 constraint.equals(query.getConstraint())); 566 } else { 567 return false; 568 } 569 } 570 571 public int hashCode() { 573 if (hasChangedHashcode) { 574 savedHashcode = (distinct? 0: 101) 575 + maxNumber * 17 + offset * 19 576 + 23 * steps.hashCode() 577 + 29 * fields.hashCode() 578 + 31 * sortOrders.hashCode() 579 + 37 * (constraint == null? 0: constraint.hashCode()); 580 hasChangedHashcode = false; 581 } 582 return savedHashcode; 583 } 584 585 public String toString() { 587 return "SearchQuery(distinct:" + isDistinct() 588 + ", steps:" + getSteps() 589 + ", fields:" + getFields() 590 + ", constraint:" + getConstraint() 591 + ", sortorders:" + getSortOrders() 592 + ", max:" + getMaxNumber() 593 + ", offset:" + getOffset() + ")"; 594 } 595 596 } 597 | Popular Tags |