1 2 12 package com.versant.core.jdo; 13 14 import com.versant.core.common.NewObjectOID; 15 import com.versant.core.metadata.ClassMetaData; 16 import com.versant.core.metadata.FetchGroup; 17 import com.versant.core.server.CompiledQuery; 18 import com.versant.core.util.BeanUtils; 19 20 import javax.jdo.Extent; 21 import javax.jdo.PersistenceManager; 22 import javax.jdo.spi.PersistenceCapable; 23 import java.io.Externalizable ; 24 import java.io.IOException ; 25 import java.io.ObjectInput ; 26 import java.io.ObjectOutput ; 27 import java.util.*; 28 29 import com.versant.core.common.BindingSupportImpl; 30 31 34 public final class VersantQueryImp implements VersantQuery, Externalizable { 35 36 private final QueryDetails queryDetails = new QueryDetails(); 37 private QueryResult resultList; 38 private PMProxy pmProxy; 39 private CompiledQuery compiledQuery; 40 41 44 public VersantQueryImp() { 45 } 46 47 51 public VersantQueryImp(PMProxy pmProxy) { 52 this(pmProxy, QueryDetails.LANGUAGE_JDOQL); 53 } 54 55 63 public VersantQueryImp(PMProxy pmProxy, int language) { 64 this.pmProxy = pmProxy; 65 queryDetails.setLanguage(language); 66 setIgnoreCache(pmProxy.getIgnoreCache()); 67 } 68 69 72 public VersantQueryImp(PMProxy pmProxy, VersantQueryImp other) { 73 this(pmProxy, other.queryDetails); 74 } 75 76 80 public VersantQueryImp(PMProxy pmProxy, QueryDetails params) { 81 this.pmProxy = pmProxy; 82 queryDetails.fillFrom(params); 83 if (params.isUseIgnoreCacheFromPM()) { 84 setIgnoreCache(pmProxy.getIgnoreCache()); 85 } 86 } 87 88 92 private void changed() { 93 compiledQuery = null; 94 } 95 96 public void setBounded(boolean value) { 97 queryDetails.setBounded(value); 98 } 99 100 public boolean isBounded() { 101 return queryDetails.isBounded(); 102 } 103 104 public void setClass(Class cls) { 105 changed(); 106 queryDetails.setCandidateClass(cls); 107 } 108 109 public void setCandidates(Extent pcs) { 110 changed(); 111 queryDetails.setExtent(pcs); 112 } 113 114 public void setCandidates(Collection pcs) { 115 changed(); 116 queryDetails.setCol(pcs); 117 } 118 119 public void setFilter(String filter) { 120 changed(); 121 queryDetails.setFilter(filter); 122 } 123 124 public String getFilter() { 125 return queryDetails.getFilter(); 126 } 127 128 public void declareImports(String imports) { 129 changed(); 130 queryDetails.setImports(imports); 131 } 132 133 public void declareParameters(String params) { 134 changed(); 135 queryDetails.declareParameters(params); 136 } 137 138 public void declareVariables(String variables) { 139 changed(); 140 queryDetails.setVariables(variables); 141 } 142 143 public void setOrdering(String ordering) { 144 changed(); 145 queryDetails.setOrdering(ordering); 146 } 147 148 public void setIgnoreCache(boolean ignoreCache) { 149 changed(); 150 queryDetails.setIgnoreCache(ignoreCache); 151 } 152 153 private VersantPersistenceManagerImp getRealPM() { 154 if (pmProxy == null) { 155 throw BindingSupportImpl.getInstance().invalidOperation( 156 "Query is not associated with a PersistenceManager"); 157 } 158 return pmProxy.getRealPM(); 159 } 160 161 public void setFetchGroup(String fgName) { 162 if (fgName == null) { 163 queryDetails.setFetchGroupIndex(0); 164 changed(); 165 return; 166 } else { 167 if (queryDetails.getCandidateClass() == null) { 168 throw BindingSupportImpl.getInstance().invalidOperation( 169 "Please first supply a candidate class"); 170 } 171 FetchGroup fg = getRealPM().modelMetaData.getClassMetaData( 172 queryDetails.getCandidateClass()).getFetchGroup(fgName); 173 if (fg == null) { 174 throw BindingSupportImpl.getInstance().invalidOperation("No fetchGroup with name " 175 + fgName 176 + " for class " 177 + queryDetails.getCandidateClass().getName()); 178 } 179 180 queryDetails.setFetchGroupIndex(fg.index); 181 changed(); 182 } 183 } 184 185 public String getFetchGroup() { 186 int i = queryDetails.getFetchGroupIndex(); 187 if (i == 0) return null; 188 ClassMetaData cmd = getRealPM().modelMetaData.getClassMetaData( 189 queryDetails.getCandidateClass()); 190 return cmd.fetchGroups[i].name; 191 } 192 193 public void setMaxRows(int amount) { 194 changed(); 195 this.queryDetails.setMaxResultCount(amount); 196 } 197 198 public int getMaxRows() { 199 return queryDetails.getMaxResultCount(); 200 } 201 202 public void setFetchSize(int value) { 203 changed(); 204 this.queryDetails.setResultBatchSize(value); 205 } 206 207 public int getFetchSize() { 208 return queryDetails.getResultBatchSize(); 209 } 210 211 public void setRandomAccess(boolean on) { 212 changed(); 213 queryDetails.setRandomAccess(on); 214 } 215 216 public boolean isRandomAccess() { 217 return queryDetails.isRandomAccess(); 218 } 219 220 public void setCountStarOnSize(boolean on) { 221 changed(); 222 queryDetails.setCountOnSize(on); 223 } 224 225 public boolean isCountStarOnSize() { 226 return queryDetails.isCountOnSize(); 227 } 228 229 public boolean getIgnoreCache() { 230 return queryDetails.isIgnoreCache(); 231 } 232 233 public void setEvictionClasses(Class [] classes, boolean includeSubclasses) { 234 setEvictionClasses(getRealPM().modelMetaData.convertToClassIndexes( 235 classes, 236 includeSubclasses)); 237 } 238 239 public void setEvictionClasses(int[] classIndexes) { 240 changed(); 241 queryDetails.setExtraEvictClasses(classIndexes); 242 } 243 244 public Class [] getEvictionClasses() { 245 int[] a = queryDetails.getExtraEvictClasses(); 246 return a == null ? null : getRealPM().modelMetaData.convertFromClassIndexes( 247 a); 248 } 249 250 public void setResult(String result) { 251 changed(); 252 queryDetails.setResult(result); 253 } 254 255 public void setGrouping(String grouping) { 256 changed(); 257 queryDetails.setGrouping(grouping); 258 } 259 260 263 public void setUnique(boolean unique) { 264 changed(); 265 queryDetails.setUnique(unique); 266 } 267 268 public void compile() { 269 if (compiledQuery == null) { 270 queryDetails.updateCounts(); 271 compiledQuery = pmProxy.getRealPM().getStorageManager().compileQuery( 272 queryDetails); 273 } 274 } 275 276 277 private 278 279 280 void checkParamCount(int n) { 281 int tc = queryDetails.getTotalParamCount(); 282 if (tc >= 0 && n != tc) { 283 throw BindingSupportImpl.getInstance().runtime( 284 "Expected " + 285 queryDetails.getTotalParamCount() + " parameters, have " + n); 286 } 287 } 288 289 public Object execute() { 290 checkParamCount(0); 291 queryDetails.updateCounts(); 292 return executeWithArrayImp(null); 293 } 294 295 public Object execute(Object p1) { 296 checkParamCount(1); 297 queryDetails.updateCounts(); 298 if (queryDetails.hasJdoGenieOptions()) { 299 processJdoGenieOptions(p1); 300 return executeWithArrayImp(null); 301 } else { 302 return executeWithArrayImp(new Object []{p1}); 303 } 304 } 305 306 public Object execute(Object p1, Object p2) { 307 checkParamCount(2); 308 queryDetails.updateCounts(); 309 switch (queryDetails.getOptionsParamIndex()) { 310 case 0: 311 processJdoGenieOptions(p1); 312 return executeWithArrayImp(new Object []{p2}); 313 case 1: 314 processJdoGenieOptions(p2); 315 return executeWithArrayImp(new Object []{p1}); 316 } 317 return executeWithArrayImp(new Object []{p1, p2}); 318 } 319 320 public Object execute(Object p1, Object p2, Object p3) { 321 checkParamCount(3); 322 queryDetails.updateCounts(); 323 switch (queryDetails.getOptionsParamIndex()) { 324 case 0: 325 processJdoGenieOptions(p1); 326 return executeWithArrayImp(new Object []{p2, p3}); 327 case 1: 328 processJdoGenieOptions(p2); 329 return executeWithArrayImp(new Object []{p1, p3}); 330 case 2: 331 processJdoGenieOptions(p2); 332 return executeWithArrayImp(new Object []{p1, p2}); 333 } 334 return executeWithArrayImp(new Object []{p1, p2, p3}); 335 } 336 337 public final Object executeWithArray(Object [] parameters) { 338 queryDetails.updateCounts(); 339 int n = parameters == null ? 0 : parameters.length; 340 checkParamCount(n); 341 int oi = queryDetails.getOptionsParamIndex(); 342 if (oi >= 0) { 343 processJdoGenieOptions(parameters[oi]); 344 if (n == 1) { 345 return executeWithArrayImp(null); 346 } 347 Object [] a = new Object [n - 1]; 348 if (oi > 0) System.arraycopy(parameters, 0, a, 0, oi); 349 if (oi < n) System.arraycopy(parameters, oi + 1, a, oi, n - oi - 1); 350 return executeWithArrayImp(a); 351 } else { 352 return executeWithArrayImp(copyParams(parameters)); 353 } 354 } 355 356 360 public VersantQueryPlan getPlan(Object [] parameters) { 361 queryDetails.updateCounts(); 362 if (queryDetails.getCol() != null) { 363 throw BindingSupportImpl.getInstance().invalidOperation( 364 "getPlan is not supported for queries executed against a collection"); 365 } 366 int n = parameters == null ? 0 : parameters.length; 367 checkParamCount(n); 368 int oi = queryDetails.getOptionsParamIndex(); 369 if (oi >= 0) { 370 processJdoGenieOptions(parameters[oi]); 371 if (n == 1) { 372 return getPlanImp(null); 373 } 374 Object [] a = new Object [n - 1]; 375 if (oi > 0) System.arraycopy(parameters, 0, a, 0, oi); 376 if (oi < n) System.arraycopy(parameters, oi, a, oi - 1, n - oi - 1); 377 return getPlanImp(a); 378 } else { 379 return getPlanImp(parameters); 380 } 381 } 382 383 public Object executeWithMap(Map parameters) { 384 queryDetails.updateCounts(); 385 int tp = queryDetails.getTotalParamCount(); 386 if (parameters.size() != tp) { 387 throw BindingSupportImpl.getInstance().runtime( 388 "The number of entries in the map (" + parameters.size() + ") " + 389 "differs from the number of declared parameters (" + tp + ")"); 390 } 391 if (tp == 0) return executeWithArrayImp(null); 392 393 Object [] pa; 395 int np = queryDetails.getParamCount(); 396 if (np > 0) { 397 pa = new Object [np]; 398 String [] names = queryDetails.getParamNames(); 399 for (int i = 0; i < np; i++) { 400 String name = names[i]; 401 if (!parameters.containsKey(name)) { 402 throw BindingSupportImpl.getInstance().runtime( 403 "Parameter '" + name + "' not found in map"); 404 } 405 pa[i] = parameters.get(name); 406 } 407 } else { 408 pa = null; 409 } 410 411 if (queryDetails.hasJdoGenieOptions()) { 413 Object o = parameters.get(VERSANT_OPTIONS); 414 if (o == null) o = parameters.get(JDO_GENIE_OPTIONS); 415 processJdoGenieOptions(o); 416 } 417 418 return executeWithArrayImp(pa); 420 } 421 422 private void processJdoGenieOptions(Object o) { 423 setFetchGroup(null); 425 setRandomAccess(false); 426 427 if (o == null) return; 429 if (!(o instanceof String )) { 430 throw BindingSupportImpl.getInstance().runtime("Invalid " + 431 VERSANT_OPTIONS + ": Expected String value: " + 432 o.getClass()); 433 } 434 String props = (String )o; 435 if (props.length() == 0) return; 436 try { 437 BeanUtils.parseProperties(props, this); 438 } catch (Exception e) { 439 throw BindingSupportImpl.getInstance().runtime( 440 "Invalid " + VERSANT_OPTIONS + ": " + e.getMessage(), e); 441 } 442 } 443 444 447 private final Object executeWithArrayImp(Object [] parameters) { 448 final PMProxy pmProxy = this.pmProxy; 449 pmProxy.getRealPM().convertPcParamsToOID(parameters); 450 if (!pmProxy.isActive() && !pmProxy.getRealPM().isNontransactionalRead()) { 451 throw BindingSupportImpl.getInstance().invalidOperation( 452 "Must set nonTransactionalRead to true"); 453 } 454 455 Class cls = queryDetails.getCandidateClass(); 457 Class [] candidates = null; 458 if (cls != null) { 459 candidates = pmProxy.getRealPM().modelMetaData.getQueryCandidatesFor(cls); 460 if (candidates == null) { 461 throw BindingSupportImpl.getInstance().unsupported("Queries for class '" 462 + queryDetails.getCandidateClass() + "' is not supported"); 463 } 464 } 465 466 if (candidates != null && candidates.length > 1) { 467 queryDetails.updateCounts(); 469 Set qResults = new HashSet(); 470 for (int i = 0; i < candidates.length; i++) { 471 Class candidate = candidates[i]; 472 473 QueryDetails qd = new QueryDetails(queryDetails); 474 qd.setCandidateClass(candidate); 475 476 CompiledQuery cq = this.pmProxy.getRealPM().getStorageManager().compileQuery(qd); 477 QueryResult qr = getQueryResult(parameters, qd, cq, this.pmProxy); 478 479 qResults.add(qr); 480 } 481 return new MultiPartQueryResult(qResults); 482 } else { 483 compile(); 484 485 if (compiledQuery.isUnique()) { 487 return QueryResultBase.resolveRow(pmProxy.getAllQueryResults( 489 compiledQuery, 490 parameters).getUnique(), 491 pmProxy); 492 } else { 493 return getQueryResult(parameters, queryDetails, compiledQuery, this.pmProxy); 494 } 495 } 496 } 497 498 private static Object [] copyParams(Object [] parameters) { 499 Object [] params = null; 500 if (parameters != null) { 501 params = new Object [parameters.length]; 502 for (int i = 0; i < params.length; i++) { 503 params[i] = parameters[i]; 504 } 505 } 506 return params; 507 } 508 509 private QueryResult getQueryResult(Object [] params, 510 QueryDetails queryDetails, CompiledQuery compiledQuery, PMProxy pmProxy) { 511 QueryResult res = null; 512 boolean collectionQuery = queryDetails.getCol() != null; 513 boolean containsNewOID = containsNewOID(params); 514 515 if (collectionQuery) { 516 res = new MemoryQueryResult(pmProxy, 518 queryDetails, createSMList(queryDetails.getCol(), pmProxy), params); 519 } else if (containsNewOID && queryDetails.isIgnoreCache()) { 520 res = new MemoryQueryResult(); 522 } else if (queryDetails.isRandomAccess()) { 523 res = new RandomAccessQueryResult(pmProxy, 525 compiledQuery, params); 526 } else { 527 res = new ForwardQueryResult(pmProxy, queryDetails, 529 compiledQuery, params); 530 } 531 if (pmProxy.getMultithreaded()) { 532 res = new SynchronizedQueryResult(pmProxy, res); 533 } 534 535 addResults(res); 536 return res; 537 } 538 539 542 private void addResults(QueryResult q) { 543 synchronized (pmProxy) { 544 if (resultList == null) { 545 resultList = q; 546 } else { 547 q.setNext(resultList); 548 resultList.setPrev(q); 549 resultList = q; 550 } 551 } 552 } 553 554 557 private void removeResults(QueryResult q) { 558 synchronized (pmProxy) { 559 if (resultList == q) { resultList = q.getNext(); 561 if (resultList != null) resultList.setPrev(null); 562 q.setNext(null); 563 } else { 564 q.getPrev().setNext(q.getNext()); 565 if (q.getNext() != null) q.getNext().setPrev(q.getPrev()); 566 q.setNext(null); 567 q.setPrev(null); 568 } 569 } 570 } 571 572 577 private VersantQueryPlan getPlanImp(Object [] parameters) { 578 VersantPersistenceManagerImp realPM = pmProxy.getRealPM(); 579 realPM.convertPcParamsToOID(parameters); 580 compile(); 581 return realPM.getStorageManager().getQueryPlan(queryDetails, 582 compiledQuery, parameters); 583 } 584 585 private static List createSMList(Collection col, PMProxy pmProxy) { 586 List tmpList = new ArrayList(); 587 for (Iterator iterator = col.iterator(); iterator.hasNext();) { 588 PersistenceCapable persistenceCapable = (PersistenceCapable)iterator.next(); 589 tmpList.add(pmProxy.getInternalSM(persistenceCapable)); 590 } 591 return tmpList; 592 } 593 594 private static boolean containsNewOID(Object [] params) { 595 if (params != null) { 596 for (int i = 0; i < params.length; i++) { 597 Object param = params[i]; 598 if (param instanceof NewObjectOID) { 599 return true; 600 } 601 } 602 } 603 return false; 604 } 605 606 public PersistenceManager getPersistenceManager() { 607 return pmProxy; 608 } 609 610 public void close(Object queryResult) { 611 QueryResult qr = (QueryResult)queryResult; 612 qr.close(); 613 removeResults(qr); 614 } 615 616 public void closeAll() { 617 synchronized (pmProxy) { 618 if (resultList == null) return; 619 resultList.close(); 620 for (QueryResult i = resultList.getNext(); i != null; i = i.getNext()) { 621 i.close(); 622 i.getPrev().setNext(null); 623 i.setPrev(null); 624 } 625 resultList = null; 626 } 627 } 628 629 public void writeExternal(ObjectOutput out) throws IOException { 630 queryDetails.writeExternal(out); 631 } 632 633 public void readExternal(ObjectInput in) throws IOException , 634 ClassNotFoundException { 635 QueryDetails qp = new QueryDetails(); 636 qp.readExternal(in); 637 this.queryDetails.fillFrom(qp); 638 } 639 640 public void initialiseFrom(VersantQueryImp clientQuery) { 641 this.queryDetails.fillFrom(clientQuery.queryDetails); 642 this.queryDetails.clearExtentAndCol(); 643 } 644 645 public void setCacheable(boolean on) { 646 changed(); 647 queryDetails.setCacheable(on); 648 } 649 650 public String getImports() { 651 return queryDetails.getImports(); 652 } 653 654 public String getParameters() { 655 return queryDetails.getParameters(); 656 } 657 658 public String getVariables() { 659 return queryDetails.getVariables(); 660 } 661 662 public String getOrdering() { 663 return queryDetails.getOrdering(); 664 } 665 666 public String getGrouping() { 667 return queryDetails.getGrouping(); 668 } 669 670 public String getResult() { 671 return queryDetails.getResult(); 672 } 673 674 public boolean isUnique() { 675 return queryDetails.getUnique() == QueryDetails.TRUE; 676 } 677 } 678 | Popular Tags |