1 2 12 package com.versant.core.ejb; 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 javax.persistence.Query; 24 import javax.persistence.TemporalType; 25 import javax.persistence.FlushModeType; 26 import java.io.Externalizable ; 27 import java.io.IOException ; 28 import java.io.ObjectInput ; 29 import java.io.ObjectOutput ; 30 import java.util.*; 31 32 import com.versant.core.common.BindingSupportImpl; 33 import com.versant.core.jdo.*; 34 35 38 public final class VersantEjbQueryImp implements Externalizable , Query { 39 private Object [] params = new Object [5]; 40 41 private final QueryDetails queryDetails = new QueryDetails(); 42 private QueryResult resultList; 43 private EMProxy pmProxy; 44 private CompiledQuery compiledQuery; 45 private int paramEndIndex = -1; 46 47 50 public VersantEjbQueryImp() { 51 } 52 53 public VersantEjbQueryImp(EMProxy emProxy, String filter) { 54 this(emProxy, QueryDetails.LANGUAGE_EJBQL); 55 queryDetails.setFilter(filter); 56 } 57 58 67 public VersantEjbQueryImp(EMProxy pmProxy, int language) { 68 this.pmProxy = pmProxy; 69 queryDetails.setLanguage(language); 70 } 71 72 76 public VersantEjbQueryImp(EMProxy pmProxy, QueryDetails params) { 77 this.pmProxy = pmProxy; 78 queryDetails.fillFrom(params); 79 } 80 81 85 private void changed() { 86 compiledQuery = null; 87 } 88 89 public List getResultList() { 90 if (paramEndIndex >= 0) { 91 if (params.length > paramEndIndex + 1) { 92 Object [] tmp = new Object [paramEndIndex + 1]; 93 System.arraycopy(params, 0, tmp, 0, tmp.length); 94 params = tmp; 95 } 96 return (List) executeWithArray(params); 97 } 98 return (List) execute(); 99 } 100 101 public Object getSingleResult() { 102 return null; 103 } 104 105 public int executeUpdate() { 106 return 0; 107 } 108 109 public Query setMaxResults(int maxResult) { 110 queryDetails.setMaxResultCount(maxResult); 111 return this; 112 } 113 114 public Query setFirstResult(int startPosition) { 115 return this; 116 } 117 118 public Query setHint(String hintName, Object value) { 119 return this; 120 } 121 122 public Query setParameter(String name, Object value) { 123 return this; 124 } 125 126 public Query setParameter(String name, Date value, TemporalType temporalType) { 127 return this; 128 } 129 130 public Query setParameter(String name, Calendar value, TemporalType temporalType) { 131 return this; 132 } 133 134 public Query setParameter(int position, Object value) { 135 if (position > paramEndIndex) { 136 paramEndIndex = position; 137 } 138 if (params.length == position) { 139 Object [] tmp = new Object [params.length + 1]; 140 System.arraycopy(params, 0, tmp, 0, params.length); 141 params = tmp; 142 } 143 params[position] = value; 144 return this; 145 } 146 147 public Query setParameter(int position, Date value, TemporalType temporalType) { 148 setParameter(position, value); 149 return this; 150 } 151 152 public Query setParameter(int position, Calendar value, TemporalType temporalType) { 153 setParameter(position, value); 154 return this; 155 } 156 157 public Query setFlushMode(FlushModeType flushMode) { 158 setIgnoreCache(flushMode != FlushModeType.AUTO); 159 return this; 160 } 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 public void setBounded(boolean value) { 180 queryDetails.setBounded(value); 181 } 182 183 public boolean isBounded() { 184 return queryDetails.isBounded(); 185 } 186 187 public void setClass(Class cls) { 188 changed(); 189 queryDetails.setCandidateClass(cls); 190 } 191 192 public void setCandidates(Extent pcs) { 193 changed(); 194 queryDetails.setExtent(pcs); 195 } 196 197 public void setCandidates(Collection pcs) { 198 changed(); 199 queryDetails.setCol(pcs); 200 } 201 202 public void setFilter(String filter) { 203 changed(); 204 queryDetails.setFilter(filter); 205 } 206 207 public String getFilter() { 208 return queryDetails.getFilter(); 209 } 210 211 public void declareImports(String imports) { 212 changed(); 213 queryDetails.setImports(imports); 214 } 215 216 public void declareParameters(String params) { 217 changed(); 218 queryDetails.declareParameters(params); 219 } 220 221 public void declareVariables(String variables) { 222 changed(); 223 queryDetails.setVariables(variables); 224 } 225 226 public void setOrdering(String ordering) { 227 changed(); 228 queryDetails.setOrdering(ordering); 229 } 230 231 public void setIgnoreCache(boolean ignoreCache) { 232 changed(); 233 queryDetails.setIgnoreCache(ignoreCache); 234 } 235 236 private EntityManagerImp getRealPM() { 237 if (pmProxy == null) { 238 throw BindingSupportImpl.getInstance().invalidOperation( 239 "Query is not associated with a PersistenceManager"); 240 } 241 return pmProxy.getEm(); 242 } 243 244 public void setFetchGroup(String fgName) { 245 if (fgName == null) { 246 queryDetails.setFetchGroupIndex(0); 247 changed(); 248 return; 249 } else { 250 if (queryDetails.getCandidateClass() == null) { 251 throw BindingSupportImpl.getInstance().invalidOperation( 252 "Please first supply a candidate class"); 253 } 254 FetchGroup fg = getRealPM().modelMetaData.getClassMetaData( 255 queryDetails.getCandidateClass()).getFetchGroup(fgName); 256 if (fg == null) { 257 throw BindingSupportImpl.getInstance().invalidOperation("No fetchGroup with name " 258 + fgName 259 + " for class " 260 + queryDetails.getCandidateClass().getName()); 261 } 262 263 queryDetails.setFetchGroupIndex(fg.index); 264 changed(); 265 } 266 } 267 268 public String getFetchGroup() { 269 int i = queryDetails.getFetchGroupIndex(); 270 if (i == 0) return null; 271 ClassMetaData cmd = getRealPM().modelMetaData.getClassMetaData( 272 queryDetails.getCandidateClass()); 273 return cmd.fetchGroups[i].name; 274 } 275 276 public void setMaxRows(int amount) { 277 changed(); 278 this.queryDetails.setMaxResultCount(amount); 279 } 280 281 public int getMaxRows() { 282 return queryDetails.getMaxResultCount(); 283 } 284 285 public void setFetchSize(int value) { 286 changed(); 287 this.queryDetails.setResultBatchSize(value); 288 } 289 290 public int getFetchSize() { 291 return queryDetails.getResultBatchSize(); 292 } 293 294 public void setRandomAccess(boolean on) { 295 changed(); 296 queryDetails.setRandomAccess(on); 297 } 298 299 public boolean isRandomAccess() { 300 return queryDetails.isRandomAccess(); 301 } 302 303 public void setCountStarOnSize(boolean on) { 304 changed(); 305 queryDetails.setCountOnSize(on); 306 } 307 308 public boolean isCountStarOnSize() { 309 return queryDetails.isCountOnSize(); 310 } 311 312 public boolean getIgnoreCache() { 313 return queryDetails.isIgnoreCache(); 314 } 315 316 public void setEvictionClasses(Class [] classes, boolean includeSubclasses) { 317 setEvictionClasses(getRealPM().modelMetaData.convertToClassIndexes( 318 classes, 319 includeSubclasses)); 320 } 321 322 public void setEvictionClasses(int[] classIndexes) { 323 changed(); 324 queryDetails.setExtraEvictClasses(classIndexes); 325 } 326 327 public Class [] getEvictionClasses() { 328 int[] a = queryDetails.getExtraEvictClasses(); 329 return a == null ? null : getRealPM().modelMetaData.convertFromClassIndexes( 330 a); 331 } 332 333 public void setResult(String result) { 334 changed(); 335 queryDetails.setResult(result); 336 } 337 338 public void setGrouping(String grouping) { 339 changed(); 340 queryDetails.setGrouping(grouping); 341 } 342 343 346 public void setUnique(boolean unique) { 347 changed(); 348 queryDetails.setUnique(unique); 349 } 350 351 public void compile() { 352 if (compiledQuery == null) { 353 queryDetails.updateCounts(); 354 compiledQuery = pmProxy.getEm().getStorageManager().compileQuery( 355 queryDetails); 356 } 357 } 358 359 363 public void checkParamCount(int n) { 364 if (n != queryDetails.getTotalParamCount()) { 365 throw BindingSupportImpl.getInstance().runtime( 366 "Expected " + 367 queryDetails.getTotalParamCount() + " parameters, have " + n); 368 } 369 } 370 371 public Object execute() { 372 queryDetails.updateCounts(); 373 return executeWithArrayImp(null); 374 } 375 376 public Object execute(Object p1) { 377 checkParamCount(1); 378 queryDetails.updateCounts(); 379 if (queryDetails.hasJdoGenieOptions()) { 380 processJdoGenieOptions(p1); 381 return executeWithArrayImp(null); 382 } else { 383 return executeWithArrayImp(new Object []{p1}); 384 } 385 } 386 387 public Object execute(Object p1, Object p2) { 388 checkParamCount(2); 389 queryDetails.updateCounts(); 390 switch (queryDetails.getOptionsParamIndex()) { 391 case 0: 392 processJdoGenieOptions(p1); 393 return executeWithArrayImp(new Object []{p2}); 394 case 1: 395 processJdoGenieOptions(p2); 396 return executeWithArrayImp(new Object []{p1}); 397 } 398 return executeWithArrayImp(new Object []{p1, p2}); 399 } 400 401 public Object execute(Object p1, Object p2, Object p3) { 402 checkParamCount(3); 403 queryDetails.updateCounts(); 404 switch (queryDetails.getOptionsParamIndex()) { 405 case 0: 406 processJdoGenieOptions(p1); 407 return executeWithArrayImp(new Object []{p2, p3}); 408 case 1: 409 processJdoGenieOptions(p2); 410 return executeWithArrayImp(new Object []{p1, p3}); 411 case 2: 412 processJdoGenieOptions(p2); 413 return executeWithArrayImp(new Object []{p1, p2}); 414 } 415 ; 416 return executeWithArrayImp(new Object []{p1, p2, p3}); 417 } 418 419 public final Object executeWithArray(Object [] parameters) { 420 queryDetails.updateCounts(); 421 int n = parameters == null ? 0 : parameters.length; 422 int oi = queryDetails.getOptionsParamIndex(); 423 if (oi >= 0) { 424 processJdoGenieOptions(parameters[oi]); 425 if (n == 1) { 426 return executeWithArrayImp(null); 427 } 428 Object [] a = new Object [n - 1]; 429 if (oi > 0) System.arraycopy(parameters, 0, a, 0, oi); 430 if (oi < n) System.arraycopy(parameters, oi + 1, a, oi, n - oi - 1); 431 return executeWithArrayImp(a); 432 } else { 433 return executeWithArrayImp(copyParams(parameters)); 434 } 435 } 436 437 441 public VersantQueryPlan getPlan(Object [] parameters) { 442 queryDetails.updateCounts(); 443 if (queryDetails.getCol() != null) { 444 throw BindingSupportImpl.getInstance().invalidOperation( 445 "getPlan is not supported for queries executed against a collection"); 446 } 447 int n = parameters == null ? 0 : parameters.length; 448 checkParamCount(n); 449 int oi = queryDetails.getOptionsParamIndex(); 450 if (oi >= 0) { 451 processJdoGenieOptions(parameters[oi]); 452 if (n == 1) { 453 return getPlanImp(null); 454 } 455 Object [] a = new Object [n - 1]; 456 if (oi > 0) System.arraycopy(parameters, 0, a, 0, oi); 457 if (oi < n) System.arraycopy(parameters, oi, a, oi - 1, n - oi - 1); 458 return getPlanImp(a); 459 } else { 460 return getPlanImp(parameters); 461 } 462 } 463 464 public Object executeWithMap(Map parameters) { 465 queryDetails.updateCounts(); 466 int tp = queryDetails.getTotalParamCount(); 467 if (parameters.size() != tp) { 468 throw BindingSupportImpl.getInstance().runtime( 469 "The number of entries in the map (" + parameters.size() + ") " + 470 "differs from the number of declared parameters (" + tp + ")"); 471 } 472 if (tp == 0) return executeWithArrayImp(null); 473 474 Object [] pa; 476 int np = queryDetails.getParamCount(); 477 if (np > 0) { 478 pa = new Object [np]; 479 String [] names = queryDetails.getParamNames(); 480 for (int i = 0; i < np; i++) { 481 String name = names[i]; 482 if (!parameters.containsKey(name)) { 483 throw BindingSupportImpl.getInstance().runtime( 484 "Parameter '" + name + "' not found in map"); 485 } 486 pa[i] = parameters.get(name); 487 } 488 } else { 489 pa = null; 490 } 491 492 if (queryDetails.hasJdoGenieOptions()) { 494 Object o = parameters.get(VersantQuery.VERSANT_OPTIONS); 495 if (o == null) o = parameters.get(VersantQuery.JDO_GENIE_OPTIONS); 496 processJdoGenieOptions(o); 497 } 498 499 return executeWithArrayImp(pa); 501 } 502 503 private void processJdoGenieOptions(Object o) { 504 setFetchGroup(null); 506 setRandomAccess(false); 507 508 if (o == null) return; 510 if (!(o instanceof String )) { 511 throw BindingSupportImpl.getInstance().runtime("Invalid " + 512 VersantQuery.VERSANT_OPTIONS + ": Expected String value: " + 513 o.getClass()); 514 } 515 String props = (String )o; 516 if (props.length() == 0) return; 517 try { 518 BeanUtils.parseProperties(props, this); 519 } catch (Exception e) { 520 throw BindingSupportImpl.getInstance().runtime( 521 "Invalid " + VersantQuery.VERSANT_OPTIONS + ": " + e.getMessage(), e); 522 } 523 } 524 525 528 private final Object executeWithArrayImp(Object [] parameters) { 529 final EMProxy pmProxy = this.pmProxy; 530 pmProxy.getEm().convertPcParamsToOID(parameters); 531 532 Class cls = queryDetails.getCandidateClass(); 534 Class [] candidates = null; 535 if (cls != null) { 536 candidates = pmProxy.getEm().modelMetaData.getQueryCandidatesFor(cls); 537 if (candidates == null) { 538 throw BindingSupportImpl.getInstance().unsupported("Queries for class '" 539 + queryDetails.getCandidateClass() + "' is not supported"); 540 } 541 } 542 543 if (candidates != null && candidates.length > 1) { 544 queryDetails.updateCounts(); 546 Set qResults = new HashSet(); 547 for (int i = 0; i < candidates.length; i++) { 548 Class candidate = candidates[i]; 549 550 QueryDetails qd = new QueryDetails(queryDetails); 551 qd.setCandidateClass(candidate); 552 553 CompiledQuery cq = this.pmProxy.getEm().getStorageManager().compileQuery(qd); 554 QueryResult qr = getQueryResult(parameters, qd, cq, this.pmProxy); 555 556 qResults.add(qr); 557 } 558 return new MultiPartQueryResult(qResults); 559 } else { 560 compile(); 561 562 if (compiledQuery.isUnique()) { 564 return QueryResultBase.resolveRow(pmProxy.getAllQueryResults( 566 compiledQuery, 567 parameters).getUnique(), 568 pmProxy); 569 } else { 570 return getQueryResult(parameters, queryDetails, compiledQuery, this.pmProxy); 571 } 572 } 573 } 574 575 private static Object [] copyParams(Object [] parameters) { 576 Object [] params = null; 577 if (parameters != null) { 578 params = new Object [parameters.length]; 579 for (int i = 0; i < params.length; i++) { 580 params[i] = parameters[i]; 581 } 582 } 583 return params; 584 } 585 586 private QueryResult getQueryResult(Object [] params, 587 QueryDetails queryDetails, CompiledQuery compiledQuery, EMProxy emProxy) { 588 QueryResult res = null; 589 boolean collectionQuery = queryDetails.getCol() != null; 590 boolean containsNewOID = containsNewOID(params); 591 592 res = new ForwardEJBQueryResult(emProxy, queryDetails, 606 compiledQuery, params); 607 if (emProxy.getMultithreaded()) { 609 res = new SynchronizedQueryResult(emProxy, res); 610 } 611 612 addResults(res); 613 return res; 614 } 615 616 619 private void addResults(QueryResult q) { 620 synchronized (pmProxy) { 621 if (resultList == null) { 622 resultList = q; 623 } else { 624 q.setNext(resultList); 625 resultList.setPrev(q); 626 resultList = q; 627 } 628 } 629 } 630 631 634 private void removeResults(QueryResult q) { 635 synchronized (pmProxy) { 636 if (resultList == q) { resultList = q.getNext(); 638 if (resultList != null) resultList.setPrev(null); 639 q.setNext(null); 640 } else { 641 q.getPrev().setNext(q.getNext()); 642 if (q.getNext() != null) q.getNext().setPrev(q.getPrev()); 643 q.setNext(null); 644 q.setPrev(null); 645 } 646 } 647 } 648 649 654 private VersantQueryPlan getPlanImp(Object [] parameters) { 655 pmProxy.getEm().convertPcParamsToOID(parameters); 656 compile(); 657 return pmProxy.getEm().getStorageManager().getQueryPlan(queryDetails, 658 compiledQuery, parameters); 659 } 660 661 private static List createSMList(Collection col, PMProxy pmProxy) { 662 List tmpList = new ArrayList(); 663 for (Iterator iterator = col.iterator(); iterator.hasNext();) { 664 PersistenceCapable persistenceCapable = (PersistenceCapable)iterator.next(); 665 tmpList.add(pmProxy.getInternalSM(persistenceCapable)); 666 } 667 return tmpList; 668 } 669 670 private static boolean containsNewOID(Object [] params) { 671 if (params != null) { 672 for (int i = 0; i < params.length; i++) { 673 Object param = params[i]; 674 if (param instanceof NewObjectOID) { 675 return true; 676 } 677 } 678 } 679 return false; 680 } 681 682 public PersistenceManager getPersistenceManager() { 683 return pmProxy.getEm(); 684 } 685 686 public void close(Object queryResult) { 687 QueryResult qr = (QueryResult)queryResult; 688 qr.close(); 689 removeResults(qr); 690 } 691 692 public void closeAll() { 693 synchronized (pmProxy) { 694 if (resultList == null) return; 695 resultList.close(); 696 for (QueryResult i = resultList.getNext(); i != null; i = i.getNext()) { 697 i.close(); 698 i.getPrev().setNext(null); 699 i.setPrev(null); 700 } 701 resultList = null; 702 } 703 } 704 705 public void writeExternal(ObjectOutput out) throws IOException { 706 queryDetails.writeExternal(out); 707 } 708 709 public void readExternal(ObjectInput in) throws IOException , 710 ClassNotFoundException { 711 QueryDetails qp = new QueryDetails(); 712 qp.readExternal(in); 713 this.queryDetails.fillFrom(qp); 714 } 715 716 public void initialiseFrom(VersantEjbQueryImp clientQuery) { 717 this.queryDetails.fillFrom(clientQuery.queryDetails); 718 this.queryDetails.clearExtentAndCol(); 719 } 720 721 public void setCacheable(boolean on) { 722 changed(); 723 queryDetails.setCacheable(on); 724 } 725 726 public String getImports() { 727 return queryDetails.getImports(); 728 } 729 730 public String getParameters() { 731 return queryDetails.getParameters(); 732 } 733 734 public String getVariables() { 735 return queryDetails.getVariables(); 736 } 737 738 public String getOrdering() { 739 return queryDetails.getOrdering(); 740 } 741 742 public String getGrouping() { 743 return queryDetails.getGrouping(); 744 } 745 746 public String getResult() { 747 return queryDetails.getResult(); 748 } 749 750 public boolean isUnique() { 751 return queryDetails.getUnique() == QueryDetails.TRUE; 752 } 753 } 754 | Popular Tags |