001// 002// Name 003// $RCSfile: KeyQuery.java,v $ 004// 005// Copyright 006// Copyright 2009-2012 Cloud Software Group, Inc. ALL RIGHTS RESERVED. 007// Cloud Software Group, Inc. Confidential Information 008// 009// History 010// $Revision: 1.1.2.17.2.4 $ $Date: 2012/11/01 05:07:21 $ 011// 012package com.kabira.platform; 013 014import java.util.ArrayList; 015import java.util.Iterator; 016import com.kabira.platform.KeyConstructor; 017import java.util.Map; 018import java.util.concurrent.ConcurrentHashMap; 019 020// 021// Common utility class that is package private so it can be shared. 022// 023class FieldEntry 024{ 025 String m_name; 026 Object m_value; 027 KeyComparisonOperator m_op; 028} 029 030 031/** 032 * Class used to define a query and obtain results using keys. 033 * <p> 034 * Instances of this class are created by KeyManager, so it has no 035 * public constructors. 036 * <p> 037 * Once a query is defined, it may be executed multiple times. 038 */ 039public final class KeyQuery<T> 040{ 041 /** 042 * Returns the results of a query. 043 * 044 * @param objectLock LockMode to apply to each instance returned. 045 * 046 * @return Iterable containing set. 047 * 048 * @exception KeyIncompleteError 049 * All the fields for the key have not been defined. 050 * <p> 051 * Executes the previously defined query and returns the resulting set. 052 * For ordered keys, the default orderBy of ASCENDING is used. 053 */ 054 public Iterable<T> getResults( 055 LockMode objectLock) 056 throws KeyIncompleteError 057 { 058 validateExecution(); 059 if (objectLock == null) 060 { 061 throw new NullPointerException(); 062 } 063 if (m_hasKeyCoverage) 064 { 065 return new KeyResultSet<T>(objectLock); 066 } 067 assert( m_descriptor.m_ordered == true ); 068 return getResults(KeyOrderedBy.ASCENDING, objectLock); 069 } 070 071 /** 072 * Returns the results for a query using an ordered key. 073 * 074 * @param orderBy 075 * @param objectLock 076 * 077 * @return Iterable containing set. 078 * 079 * @exception KeyIncompleteError 080 * All the fields for the key have not been defined. 081 * 082 * @exception KeyIllegalKeyTypeError 083 * The key is not ordered. 084 * <p> 085 * Executes the previously defined query and returns the resulting set. 086 */ 087 public Iterable<T> getResults( 088 KeyOrderedBy orderBy, 089 LockMode objectLock) 090 throws KeyIncompleteError 091 { 092 validateExecution(); 093 validateOrdered(); 094 if (objectLock == null) 095 { 096 throw new NullPointerException(); 097 } 098 return new KeyResultSet<T>(orderBy, objectLock); 099 } 100 101 /** 102 * Returns the instance matching the given unique key. 103 * 104 * @param objectLock The object lock applied if an instance is found. 105 * 106 * @return Object containing result, or null if key not found. 107 * 108 * @exception KeyIncompleteError 109 * The fields for the key have not been defined. 110 * 111 * @exception KeyIllegalKeyTypeError 112 * The key is not unique. 113 * <p> 114 * Executes the previously defined query and returns an instance. 115 */ 116 public T getSingleResult(LockMode objectLock) 117 throws KeyIncompleteError, KeyIllegalKeyTypeError 118 { 119 validateExecution(); 120 if ((m_descriptor.m_unique == false) || 121 (m_descriptor.m_ordered == true && m_hasKeyCoverage == false)) 122 { 123 throw new KeyIllegalKeyTypeError( 124 "Key is not unique"); 125 } 126 return attachObject(objectLock, KeyOptNoPlaceholder); 127 } 128 129 /** 130 * Returns the mininum value for the given ordered key. 131 * 132 * @param objectLock The object lock applied if an instance is found. 133 * 134 * @return Object containing result, or null if key not found. 135 * 136 * @exception KeyIllegalKeyTypeError 137 * The key is not ordered. 138 * 139 * @exception KeyMalformedQueryError 140 * An illegal operator was used when defining the query. 141 * <p> 142 * Executes the previously defined query (if any) and returns an 143 * instance containing the minimum value. If no query was defined, 144 * the instance containing the minimum key is returned. If a query was 145 * defined, the instance containing the minimum key value that 146 * matches the given fields is returned. 147 */ 148 public T getMinimumResult(LockMode objectLock) 149 throws KeyMalformedQueryError, KeyIllegalKeyTypeError 150 { 151 validateOrdered(); 152 if (m_query == null) 153 { 154 m_query = new CompiledQuery(); 155 m_query.m_keyInfo1 = new KeyInfo(); 156 } 157 CompiledQuery query = m_query; 158 if (m_query.m_filters != null) 159 { 160 query = compileOrderedQuery(CompileFilter.FILTER_NONE); 161 } 162 validateMinMaxQuery(query); 163 return attachMinimum(query, objectLock); 164 } 165 166 /** 167 * Returns the maximum value for the given ordered key. 168 * 169 * @param objectLock The object lock applied if an instance is found. 170 * 171 * @return Object containing result, or null if key not found. 172 * 173 * @exception KeyIllegalKeyTypeError 174 * The key is not ordered. 175 * 176 * @exception KeyMalformedQueryError 177 * An illegal operator was used when defining the query. 178 * <p> 179 * Executes the previously defined query (if any) and returns an 180 * instance containing the maximum value. If no query was defined, 181 * the instance containing the maximum key is returned. If a query was 182 * defined, the instance containing the maximum key value that 183 * matches the given fields is returned. 184 */ 185 public T getMaximumResult(LockMode objectLock) 186 throws KeyMalformedQueryError, KeyIllegalKeyTypeError 187 { 188 validateOrdered(); 189 if (m_query == null) 190 { 191 m_query = new CompiledQuery(); 192 m_query.m_keyInfo1 = new KeyInfo(); 193 } 194 CompiledQuery query = m_query; 195 if (m_query.m_filters != null) 196 { 197 query = compileOrderedQuery(CompileFilter.FILTER_NONE); 198 } 199 validateMinMaxQuery(query); 200 return attachMaximum(query, objectLock); 201 } 202 203 /** 204 * Returns the instance for the given unique key. 205 * 206 * @param objectLock The object lock applied if a pre-existing instance 207 * is found. 208 * @param additionalFields Additional field values to use if an 209 * instance in created. These values are ignored if 210 * the instance already exists. null can be specified 211 * if no additional field values are needed. 212 * 213 * @return Object containing result. 214 * 215 * @exception KeyIncompleteError 216 * The fields for the key have not been defined. 217 * 218 * @exception KeyIllegalKeyTypeError 219 * The key is not unique. 220 * 221 * @exception KeyIllegalFieldError 222 * A field in the additionalFields list is not valid. 223 * <p> 224 * Executes the previously defined query and returns an instance. 225 * This method will atomically insure that an instance of 226 * the type will be created when searching for a instance by key. 227 * The additionalFields list passed in allows the programmer to 228 * populate secondary key fields if the instance is created. 229 * This should be used instead of doing: 230 *<pre> 231KeyedObject ko = kq.getSingleResult(lockMode); 232if (ko == null) 233{ 234 ko = new KeyedObject(keys); 235}</pre> 236 * <p> 237 * The above new can throw an ObjectNotUniqueError exception 238 * if another transaction creates the instance between the 239 * getSingleResult() and the new call. 240 */ 241 @SuppressWarnings("unchecked") 242 public T getOrCreateSingleResult( 243 LockMode objectLock, 244 KeyFieldValueList additionalFields) 245 throws KeyIncompleteError, KeyIllegalKeyTypeError, 246 KeyIllegalFieldError 247 { 248 validateExecution(); 249 if (m_descriptor.m_unique == false) 250 { 251 throw new KeyIllegalKeyTypeError( 252 "Key is not unique"); 253 } 254 255 ArrayList<CreateBuffer> createValues = null; 256 257 if (additionalFields != null) 258 { 259 createValues = new ArrayList<CreateBuffer>(); 260 for (FieldEntry fe : additionalFields.m_entries) 261 { 262 // 263 // We need to audit that these fields are 264 // not part of the key. Otherwise we'll 265 // create the wrong instance in the "on 266 // empty" case, since the key will 267 // subsequently be updated. 268 // 269 if (findField(fe)) 270 { 271 throw new KeyIllegalFieldError( 272 "Field " + fe.m_name + 273 " in additionalFields list " + 274 "is part of the key."); 275 } 276 CreateBuffer cb = new CreateBuffer(fe); 277 createValues.add(cb); 278 } 279 } 280 281 T obj = null; 282 boolean retry = true; 283 int retryCount = 0; 284 while (retry) 285 { 286 obj = attachObject(objectLock, KeyOptNoPlaceholder); 287 if (obj != null) 288 { 289 retry = false; 290 } 291 else 292 { 293 try 294 { 295 // 296 // Attempt to create the key'd object using the 297 // constructor. The placeholder created above will 298 // prevent another transaction from creating the 299 // instance from underneath us. 300 // 301 // Note: we cast and use the above SuppressWarnings 302 // annotation since KeyConstructor uses reflection so it 303 // cannot be a generic. 304 // 305 KeyConstructor kc = new KeyConstructor(); 306 for (FieldEntry fe : m_entries) 307 { 308 kc.addKeyValue(fe.m_name, fe.m_value); 309 } 310 if (additionalFields != null) 311 { 312 for (FieldEntry fe : additionalFields.m_entries) 313 { 314 kc.addKeyValue(fe.m_name, fe.m_value); 315 } 316 } 317 obj = (T)kc.invokeConstructor(m_descriptor.m_className); 318 if (obj == null) 319 { 320 // 321 // Cannot construct instance, create a shared 322 // memory image. 323 // 324 obj = createObject(createValues); 325 } 326 retry = false; 327 } 328 catch (ObjectNotUniqueError ex) 329 { 330 if (retryCount++ > MaxSelectRetries) 331 { 332 throw ex; 333 } 334 // 335 // Just ignore this exception, we'll try and select again. 336 // 337 } 338 } 339 } 340 return obj; 341 } 342 343 /** 344 * Returns the number of instances of the given key. 345 * 346 * @return Number of instances. 347 * 348 * @exception KeyIncompleteError 349 * All the fields for the key have not been defined. 350 * <p> 351 * Executes the previously defined query and returns the number of 352 * instances that would result. 353 * <p> 354 * No transaction locks are take when this method executes. 355 * This means the number returned by cardinality() may 356 * change even if called multiple times within a single 357 * transaction. 358 * 359 */ 360 public int cardinality() 361 throws KeyIncompleteError 362 { 363 validateExecution(); 364 365 KeyIterator<T> ki = new KeyIterator<T>( 366 KeyOrderedBy.ASCENDING, 367 LockMode.NOLOCK); 368 369 return ki.size(); 370 } 371 372 /** 373 * Defines the fields that form a key query. 374 * 375 * @param keyFields The fields to use. 376 * 377 * @exception KeyIncompleteError 378 * All the fields for the key have not been defined. 379 * 380 * @exception KeyIllegalFieldError 381 * A given field is not part of the key. 382 * 383 * @exception KeyMalformedQueryError 384 * The resulting key lookup cannot perform a range query 385 * on an ordered key, or duplicate fields exist 386 * for a non-ordered key. 387 * <p> 388 * When executed, this defines the values used for a key lookup. 389 * Any previous query is overwritten. 390 */ 391 public void defineQuery( 392 KeyFieldValueList keyFields) 393 throws KeyIllegalFieldError, KeyMalformedQueryError 394 { 395 processFields(keyFields.getEntries()); 396 397 if (!m_descriptor.m_ordered && !m_hasKeyCoverage) 398 { 399 // 400 // Build missing list. Note that we ignore dups, since 401 // KeyMalformedQueryError is thrown when this happens. 402 // 403 String missing = ""; 404 for (FieldDescriptor fd : m_descriptor.m_fields) 405 { 406 boolean found = false; 407 for (FieldEntry fe : m_entries) 408 { 409 if (fd.m_name.equals(fe.m_name)) 410 { 411 found = true; 412 break; 413 } 414 } 415 if (found == false) 416 { 417 missing += ", missing field '" + fd.m_name + "'"; 418 } 419 } 420 throw new KeyIncompleteError( 421 "Not all required fields are present" + missing); 422 } 423 else if (!m_hasKeyCoverage) 424 { 425 validateOrderedKey(); 426 } 427 428 m_query = compileQuery(); 429 } 430 431 /** 432 * Defines the fields that form a range query. 433 * 434 * @param keyFields The fields to use. 435 * 436 * @exception KeyIllegalFieldError 437 * A given field is not part of the key. 438 * 439 * @exception KeyMalformedQueryError 440 * The resulting key lookup cannot perform a range query 441 * on an ordered key, duplicate fields are defined 442 * for a non-ordered key, or a range query was attempted 443 * on a non-ordered key. 444 * <p> 445 * When executed, this defines the values used for a range query 446 * on an ordered key. Any previous query is overwritten. 447 */ 448 public void defineQuery( 449 KeyFieldValueRangeList keyFields) 450 throws KeyIllegalFieldError, KeyMalformedQueryError 451 { 452 validateOrdered(); 453 454 processFields(keyFields.getEntries()); 455 456 if (!m_hasKeyCoverage) 457 { 458 validateOrderedKey(); 459 } 460 461 m_query = compileQuery(); 462 } 463 464 /** 465 * Creates a human readable query string. 466 * 467 * @exception KeyIncompleteError 468 * All the fields for the key have not been defined. 469 * <p> 470 * This method returns a string containing a "select" or "for" 471 * statement. The string also contains any optimization warnings for 472 * the defined query. 473 * This information can be used to help diagnose queries. 474 */ 475 public String toString() 476 throws KeyIncompleteError 477 { 478 String res = new String(); 479 480 if (m_descriptor.m_unique && m_hasKeyCoverage) 481 { 482 res += "select obj from "; 483 } 484 else 485 { 486 res += "for obj in "; 487 } 488 res += m_descriptor.m_className; 489 res += " using "; 490 res += m_descriptor.m_keyName; 491 res += " where ("; 492 493 boolean firstField = true; 494 for (FieldEntry fe : m_entries) 495 { 496 if (!firstField) 497 { 498 res += " && "; 499 } 500 else 501 { 502 firstField = false; 503 } 504 res += fe.m_name; 505 res += getComparisonOp(fe.m_op); 506 res += fe.m_value; 507 } 508 res += ")"; 509 if (m_descriptor.m_unique && m_hasKeyCoverage) 510 { 511 res += ";"; 512 } 513 else 514 { 515 res += " { }"; 516 } 517 518 if (m_descriptor.m_unique && m_hasKeyCoverage) 519 { 520 KeyConstructor kc = new KeyConstructor(); 521 for (FieldEntry fe : m_entries) 522 { 523 kc.addKeyValue(fe.m_name, fe.m_value); 524 } 525 res += " Java constructor: "; 526 res += kc.displayConstructor(m_descriptor.m_className); 527 } 528 529 if (m_query != null && m_query.m_filters != null) 530 { 531 for (int i = 0; i < m_query.m_filters.size(); i++) 532 { 533 KeyInfo filter = m_query.m_filters.get(i); 534 int keyDepth = 0; 535 536 for (FieldDescriptor fd : m_descriptor.m_fields) 537 { 538 if (keyDepth == filter.m_keyDepth) 539 { 540 res += " [ Warning: field '"; 541 res += fd.m_name; 542 res += "' filtered ]"; 543 break; 544 } 545 keyDepth++; 546 } 547 } 548 } 549 550 return res; 551 } 552 553 ///////////////////////////////////////////////////////////////// 554 // 555 // Private fields, classes and utility routines 556 // 557 ///////////////////////////////////////////////////////////////// 558 559 // 560 // Note: The following enumeration "know" about the actual values 561 // in the C++ enum definitions. We use them instead of java enums 562 // to avoid having to map things in JNI code. 563 // 564 565 // enumeration values for SWRBTree::RBDirection 566 private static final int SWRBTreeAscending = 1; 567 private static final int SWRBTreeDescending = 2; 568 569 // enumeration values for OSKeyOpt::Placeholder 570 private static final int KeyOptCreatePlaceholder= 1; 571 private static final int KeyOptNoPlaceholder = 2; 572 573 // enumeration values for OSKeyOpt::ObjectLock 574 private static final int KeyOptReadLock = 1; 575 private static final int KeyOptWriteLock = 2; 576 private static final int KeyOptNoLock = 3; 577 578 // enumeration values for CGObject::MaxSelectRetries 579 private static final int MaxSelectRetries = 10; 580 581 // enumeration values for ObjSrv::RangeOperator 582 private static final int ObjSrv_EQ = 1; 583 private static final int ObjSrv_NEQ = 2; 584 private static final int ObjSrv_GTE = 3; 585 private static final int ObjSrv_GT = 4; 586 private static final int ObjSrv_LTE = 5; 587 private static final int ObjSrv_LT = 6; 588 589 // enumeration values for DSETypeCode 590 private static final int tkInvalid = 0; 591 private static final int tkShort = 1; 592 private static final int tkLong = 2; 593 private static final int tkLongLong = 3; 594 private static final int tkUShort = 4; 595 private static final int tkULong = 5; 596 private static final int tkULongLong = 6; 597 private static final int tkFloat = 7; 598 private static final int tkDouble = 8; 599 private static final int tkBoolean = 9; 600 private static final int tkChar = 10; 601 private static final int tkOctet = 11; 602 private static final int tkObjectReference = 12; 603 private static final int tkStruct = 13; 604 private static final int tkEnum = 14; 605 private static final int tkString = 15; 606 private static final int tkSequence = 16; 607 private static final int tkArray = 17; 608 private static final int tkException = 18; 609 private static final int tkVoid = 19; 610 private static final int tkOffset = 20; 611 private static final int tkSize = 21; 612 private static final int tkWChar = 22; 613 private static final int tkAny = 23; 614 private static final int tkNative = 24; 615 private static final int tkType = 25; 616 private static final int tkUnion = 26; 617 private static final int tkDate = 27; 618 619 enum CompileFilter 620 { 621 FILTER_LTEGTE, 622 FILTER_NONE 623 } 624 625 // 626 // Return a string containing the Java type for the given typeCode 627 // 628 private static String getTCString(int tc) 629 { 630 String ret = "<unknown>"; 631 switch (tc) 632 { 633 case tkShort: 634 case tkUShort: 635 ret = "short"; 636 break; 637 case tkLong: 638 case tkULong: 639 ret = "int"; 640 break; 641 case tkULongLong: 642 case tkLongLong: 643 ret = "long"; 644 break; 645 case tkFloat: 646 ret = "float"; 647 break; 648 case tkDouble: 649 ret = "double"; 650 break; 651 case tkBoolean: 652 ret = "boolean"; 653 break; 654 case tkWChar: 655 ret = "char"; 656 break; 657 case tkChar: 658 case tkOctet: 659 ret = "byte"; 660 break; 661 case tkObjectReference: 662 ret = "Object"; 663 break; 664 case tkString: 665 ret = "String"; 666 break; 667 case tkDate: 668 ret = "java.util.Date"; 669 break; 670 default: 671 break; 672 } 673 return ret; 674 } 675 676 // 677 // Return a string containing the operation 678 // 679 private static String getComparisonOp(KeyComparisonOperator op) 680 { 681 String ret = null; 682 switch (op) 683 { 684 case EQ: 685 ret = " == "; 686 break; 687 case NEQ: 688 ret = " != "; 689 break; 690 case GTE: 691 ret = " >= "; 692 break; 693 case GT: 694 ret = " > "; 695 break; 696 case LTE: 697 ret = " <= "; 698 break; 699 case LT: 700 ret = " < "; 701 break; 702 } 703 return ret; 704 } 705 706 // 707 // Return the KTP typeCode for the given java object 708 // 709 private static int getTypeCode(Object obj) 710 { 711 int typeCode = tkInvalid; 712 if (obj instanceof Integer) 713 { 714 typeCode = tkLong; 715 } 716 else if (obj instanceof Long) 717 { 718 typeCode = tkLongLong; 719 } 720 else if (obj instanceof String) 721 { 722 typeCode = tkString; 723 } 724 else if (obj instanceof Short) 725 { 726 typeCode = tkShort; 727 } 728 else if (obj instanceof Character) 729 { 730 typeCode = tkWChar; 731 } 732 else if (obj instanceof Float) 733 { 734 typeCode = tkFloat; 735 } 736 else if (obj instanceof Double) 737 { 738 typeCode = tkDouble; 739 } 740 else if (obj instanceof Enum) 741 { 742 typeCode = tkEnum; 743 } 744 else if (obj instanceof java.util.Date) 745 { 746 typeCode = tkDate; 747 } 748 else if (obj instanceof Boolean) 749 { 750 typeCode = tkBoolean; 751 } 752 else if (obj instanceof Byte) 753 { 754 typeCode = tkOctet; 755 } 756 else 757 { 758 typeCode = tkObjectReference; 759 } 760 assert( typeCode != tkInvalid ); 761 return typeCode; 762 } 763 // 764 // Return the number of bytes a null key slot would contain for 765 // the given typeCode. Used when building key filters. 766 // 767 private static int getKeyOffset(int tc) 768 { 769 int size = 0; 770 switch (tc) 771 { 772 case tkShort: 773 case tkUShort: 774 size = 2; 775 break; 776 case tkLong: 777 case tkULong: 778 case tkFloat: 779 case tkWChar: 780 case tkEnum: 781 size = 4; 782 break; 783 case tkULongLong: 784 case tkLongLong: 785 case tkDouble: 786 case tkDate: 787 size = 8; 788 break; 789 case tkBoolean: 790 case tkChar: 791 case tkOctet: 792 size = 1; 793 break; 794 case tkObjectReference: 795 size = 24; 796 break; 797 case tkString: 798 size = 8; // zero length string 799 break; 800 } 801 assert( size != 0 ); 802 return size; 803 } 804 805 // 806 // Descriptors used to manage key information 807 // 808 private static class FieldDescriptor 809 { 810 FieldDescriptor(String name, int typeCode) 811 { 812 m_name = name; 813 m_typeCode = typeCode; 814 } 815 private final String m_name; 816 private final int m_typeCode; 817 818 // 819 // Return runtime mapping as per the ERD. 820 // 821 int getTypeCode() 822 { 823 int typeCode = m_typeCode; 824 switch (typeCode) 825 { 826 case tkChar: 827 typeCode = tkOctet; 828 break; 829 case tkUShort: 830 typeCode = tkShort; 831 break; 832 case tkULong: 833 typeCode = tkLong; 834 break; 835 case tkULongLong: 836 typeCode = tkLongLong; 837 break; 838 default: 839 break; 840 } 841 assert( typeCode != tkInvalid ); 842 return typeCode; 843 } 844 } 845 846 private static Map<String, KeyDescriptor> m_map = 847 new ConcurrentHashMap<String, KeyDescriptor>(); 848 849 private static class KeyDescriptor 850 { 851 KeyDescriptor(String className, String keyName) 852 { 853 m_className = className; 854 m_keyName = keyName; 855 m_fields = new ArrayList<FieldDescriptor>(); 856 m_ordered = false; 857 m_unique = false; 858 } 859 // 860 // These are define by the KeyQuery() constructor 861 // 862 private final String m_className; 863 private final String m_keyName; 864 // 865 // These are all populated by _getKeyDescriptor() 866 // 867 private ArrayList<FieldDescriptor> m_fields; 868 private boolean m_ordered; 869 private boolean m_unique; 870 private int m_objDomainId; 871 private int m_objTypeId; 872 private int m_keyDomainId; 873 private int m_keyTypeId; 874 } 875 876 // 877 // Low level buffer class that maps to the KTP runtime. 878 // 879 // Types supported (from ERD) 880 // 881 // o All basic Java types (boolean, byte, char, short, 882 // int, long, float, double) 883 // 884 // o Wrapper classes for the basic Java types 885 // (Integer, Short, Character, etc.) 886 // 887 // o java.lang.String; 888 // 889 // o java.util.Date; 890 // 891 // o Enum types; 892 // 893 // o Managed Object types. 894 // 895 private static class KeyBuffer extends AnyBuffer 896 { 897 void addData(Object obj) 898 { 899 boolean wasPut = putObject(obj); 900 assert( wasPut ); 901 } 902 } 903 904 private static class KeyInfo extends KeyBuffer 905 { 906 KeyInfo() 907 { 908 m_rop = ObjSrv_EQ; 909 m_keyDepth = 1; 910 } 911 KeyInfo(int rop) 912 { 913 m_rop = rop; 914 m_keyDepth = 1; 915 } 916 void addKeyData(Object obj) 917 { 918 addData(obj); 919 } 920 int m_rop; 921 int m_keyDepth; 922 } 923 924 private static class CreateBuffer extends KeyBuffer 925 { 926 CreateBuffer(FieldEntry fe) throws KeyIllegalFieldError 927 { 928 m_name = fe.m_name; 929 m_typeCode = getTypeCode(fe.m_value); 930 try 931 { 932 writeObject(fe.m_value); 933 } 934 catch (IllegalArgumentException iae) 935 { 936 throw new KeyIllegalFieldError( 937 "Field " + fe.m_name + " containing " + 938 fe.m_value.getClass() + " is not supported"); 939 } 940 } 941 String m_name; 942 int m_typeCode; 943 } 944 945 // 946 // Class containing a compiled query 947 // 948 private static class CompiledQuery 949 { 950 CompiledQuery() 951 { 952 m_keyInfo1 = null; 953 m_keyInfo2 = null; 954 m_filters = null; 955 m_hasRange = false; 956 } 957 958 void addRange(KeyInfo keyInfo) 959 { 960 if (m_keyInfo1 == null) 961 { 962 m_keyInfo1 = keyInfo; 963 } 964 else 965 { 966 assert( m_keyInfo2 == null ); 967 m_keyInfo2 = keyInfo; 968 } 969 m_hasRange = true; 970 } 971 972 void addKeyInfo(KeyInfo keyInfo) 973 { 974 assert( !m_hasRange ); 975 assert( m_keyInfo1 == null ); 976 m_keyInfo1 = keyInfo; 977 } 978 979 void addFilter(KeyInfo keyInfo) 980 { 981 assert( m_hasRange ); 982 if (m_filters == null) 983 { 984 m_filters = new ArrayList<KeyInfo>(); 985 } 986 m_filters.add(keyInfo); 987 } 988 989 KeyInfo m_keyInfo1; 990 KeyInfo m_keyInfo2; 991 ArrayList<KeyInfo> m_filters; 992 boolean m_hasRange; 993 } 994 995 // 996 // Private data members that use the above private classes 997 // 998 private KeyDescriptor m_descriptor; 999 private CompiledQuery m_query; 1000 private ArrayList<FieldEntry> m_entries; 1001 private boolean m_hasKeyCoverage; 1002 1003 // 1004 // Class that implements the Iterable returned from getResults() 1005 // 1006 private class KeyResultSet<T extends Object> 1007 implements Iterable<T> 1008 { 1009 KeyOrderedBy m_orderBy; 1010 LockMode m_objectLock; 1011 1012 KeyResultSet(KeyOrderedBy orderBy, LockMode objectLock) 1013 { 1014 m_orderBy = orderBy; 1015 m_objectLock = objectLock; 1016 } 1017 KeyResultSet(LockMode objectLock) 1018 { 1019 m_orderBy = KeyOrderedBy.ASCENDING; 1020 m_objectLock = objectLock; 1021 } 1022 1023 public Iterator<T> iterator() 1024 { 1025 return new KeyIterator<T>(m_orderBy, m_objectLock); 1026 } 1027 } 1028 1029 // 1030 // Class that implements the Iterator returned from Iterable 1031 // 1032 private class KeyIterator<T extends Object> 1033 implements java.util.Iterator<T> 1034 { 1035 private long m_cHandle; 1036 private T m_next; 1037 1038 KeyIterator(KeyOrderedBy orderBy, LockMode objectLock) 1039 { 1040 assert( m_query.m_keyInfo1 != null ); 1041 if (m_query.m_hasRange == false) 1042 { 1043 m_cHandle = _initKey( 1044 m_descriptor.m_objDomainId, 1045 m_descriptor.m_objTypeId, 1046 m_descriptor.m_keyDomainId, 1047 m_descriptor.m_keyTypeId, 1048 mapObjectLock(objectLock), 1049 m_query.m_keyInfo1.array()); 1050 } 1051 else if (m_query.m_keyInfo2 == null) 1052 { 1053 assert( m_query.m_hasRange == true ); 1054 assert( m_query.m_keyInfo2 == null ); 1055 Object [] filters = (m_query.m_filters == null) 1056 ? null : m_query.m_filters.toArray(); 1057 m_cHandle = _initRange1( 1058 m_descriptor.m_objDomainId, 1059 m_descriptor.m_objTypeId, 1060 m_descriptor.m_keyDomainId, 1061 m_descriptor.m_keyTypeId, 1062 mapOrderBy(orderBy), 1063 mapObjectLock(objectLock), 1064 m_query.m_keyInfo1.m_keyDepth, 1065 m_query.m_keyInfo1.m_rop, 1066 m_query.m_keyInfo1.array(), 1067 filters); 1068 } 1069 else 1070 { 1071 assert( m_query.m_hasRange == true ); 1072 assert( m_query.m_keyInfo2 != null ); 1073 Object [] filters = (m_query.m_filters == null) 1074 ? null : m_query.m_filters.toArray(); 1075 m_cHandle = _initRange2( 1076 m_descriptor.m_objDomainId, 1077 m_descriptor.m_objTypeId, 1078 m_descriptor.m_keyDomainId, 1079 m_descriptor.m_keyTypeId, 1080 mapOrderBy(orderBy), 1081 mapObjectLock(objectLock), 1082 m_query.m_keyInfo1.m_keyDepth, 1083 m_query.m_keyInfo1.m_rop, 1084 m_query.m_keyInfo1.array(), 1085 m_query.m_keyInfo2.m_keyDepth, 1086 m_query.m_keyInfo2.m_rop, 1087 m_query.m_keyInfo2.array(), 1088 filters); 1089 } 1090 m_next = _next(m_cHandle); 1091 } 1092 1093 public boolean hasNext() 1094 { 1095 return (m_next != null); 1096 } 1097 1098 public T next() 1099 { 1100 T t = m_next; 1101 1102 m_next = _next(m_cHandle); 1103 1104 return t; 1105 } 1106 1107 public void remove() 1108 { 1109 throw new UnsupportedOperationException(); 1110 } 1111 1112 protected void finalize() 1113 { 1114 if (m_cHandle != 0) 1115 { 1116 _delete(m_cHandle); 1117 } 1118 m_cHandle = 0; 1119 } 1120 1121 int size() 1122 { 1123 return _size(m_cHandle); 1124 } 1125 1126 native long _initKey( 1127 int objDomainId, 1128 int objTypeId, 1129 int keyDomainId, 1130 int keyTypeId, 1131 int objLock, 1132 byte [] keyData); 1133 native long _initRange1( 1134 int objDomainId, 1135 int objTypeId, 1136 int keyDomainId, 1137 int keyTypeId, 1138 int direction, 1139 int objLock, 1140 int keyDepth, 1141 int rop, 1142 byte [] keyData, 1143 Object [] filters); 1144 native long _initRange2( 1145 int objDomainId, 1146 int objTypeId, 1147 int keyDomainId, 1148 int keyTypeId, 1149 int direction, 1150 int objLock, 1151 int keyDepth1, 1152 int rop1, 1153 byte [] keyData1, 1154 int keyDepth2, 1155 int rop2, 1156 byte [] keyData2, 1157 Object [] filters); 1158 1159 native int _size(long cHandle); 1160 native T _next(long cHandle); 1161 native void _delete(long cHandle); 1162 } 1163 1164 // 1165 // Constructors are not exposed. 1166 // 1167 private KeyQuery() { } 1168 KeyQuery( 1169 final java.lang.Class<T> klass, 1170 final String keyName) throws KeyUnknownKeyNameError 1171 { 1172 String keyDescriptorKey = klass.getName() + "." + keyName; 1173 1174 m_descriptor = m_map.get(keyDescriptorKey); 1175 1176 if (m_descriptor == null) 1177 { 1178 m_descriptor = new KeyDescriptor(klass.getName(), keyName); 1179 1180 if (!_getKeyDescriptor(m_descriptor)) 1181 { 1182 throw new KeyUnknownKeyNameError( 1183 "Unknown keyName " + keyName); 1184 } 1185 1186 // No synchronization is needed here. If two threads 1187 // get here at the same time, the second put will replace 1188 // the first, and the GC will clean up at some later time. 1189 m_map.put(keyDescriptorKey, m_descriptor); 1190 } 1191 m_hasKeyCoverage = false; 1192 } 1193 1194 private void processFields(ArrayList<FieldEntry> entries) 1195 throws KeyIllegalFieldError, KeyMalformedQueryError 1196 { 1197 // 1198 // Clear out previous query to insure validateExecution() 1199 // fails if the new query encounters an error. 1200 // 1201 m_query = null; 1202 1203 // 1204 // entries contains a copy of the FieldEntry array defined by 1205 // the user. We keep a copy around mostly for so that 1206 // toString() can access it, otherwise we could just pass 1207 // it around for processing and compilation. 1208 // 1209 m_entries = entries; 1210 1211 // 1212 // Validate the fields we just stored. 1213 // 1214 validateFields(); 1215 1216 // 1217 // Determine if the fields cover the key. 1218 // 1219 checkForKeyCoverage(); 1220 } 1221 1222 private void validateFields() 1223 throws KeyIllegalFieldError, KeyMalformedQueryError 1224 { 1225 // 1226 // Validate each field 1227 // 1228 int count = 0; 1229 for (FieldEntry fe : m_entries) 1230 { 1231 validateField(fe); 1232 count += 1; 1233 } 1234 if (count == 0) 1235 { 1236 throw new KeyMalformedQueryError("No fields defined"); 1237 } 1238 1239 // 1240 // Check for dups 1241 // 1242 if ((!m_descriptor.m_ordered) && (count > 1)) 1243 { 1244 validateNoDups(); 1245 } 1246 } 1247 1248 private void validateField(FieldEntry fe) 1249 throws KeyIllegalFieldError, KeyMalformedQueryError 1250 { 1251 boolean found = false; 1252 1253 for (FieldDescriptor fd : m_descriptor.m_fields) 1254 { 1255 if (fe.m_name.equals(fd.m_name)) 1256 { 1257 validateValue(fd, fe.m_value); 1258 found = true; 1259 } 1260 } 1261 if (!found) 1262 { 1263 throw new KeyIllegalFieldError( 1264 "Field " + fe.m_name + 1265 " is not part of the key"); 1266 } 1267 } 1268 1269 private boolean findField(FieldEntry fe) 1270 { 1271 boolean found = false; 1272 1273 for (FieldDescriptor fd : m_descriptor.m_fields) 1274 { 1275 if (fe.m_name.equals(fd.m_name)) 1276 { 1277 return true; 1278 } 1279 } 1280 return false; 1281 } 1282 1283 private void validateNoDups() 1284 throws KeyMalformedQueryError 1285 { 1286 assert( !m_descriptor.m_ordered ); 1287 1288 for (FieldDescriptor fd : m_descriptor.m_fields) 1289 { 1290 int count = 0; 1291 for (FieldEntry fe : m_entries) 1292 { 1293 if (fd.m_name.equals(fe.m_name)) 1294 { 1295 count += 1; 1296 } 1297 } 1298 if (count > 1) 1299 { 1300 throw new KeyMalformedQueryError( 1301 "Field " + fd.m_name + 1302 " exists more than once in " + 1303 "the KeyFieldValueList list"); 1304 } 1305 } 1306 } 1307 1308 private void validateValue(FieldDescriptor fd, Object value) 1309 throws KeyIllegalFieldError 1310 { 1311 assert( value != null ); 1312 1313 int typeCode = getTypeCode(value); 1314 1315 if (typeCode != fd.getTypeCode()) 1316 { 1317 throw new KeyIllegalFieldError( 1318 "Illegal type " + getTCString(typeCode) + 1319 " for field " + fd.m_name + ", expected " + 1320 getTCString(fd.getTypeCode())); 1321 } 1322 } 1323 1324 private void checkForKeyCoverage() 1325 { 1326 // 1327 // If any of the field entries are not ==, we don't have 1328 // key coverage. 1329 // 1330 for (FieldEntry fe : m_entries) 1331 { 1332 if (fe.m_op != KeyComparisonOperator.EQ) 1333 { 1334 m_hasKeyCoverage = false; 1335 return; 1336 } 1337 } 1338 1339 // 1340 // If all fields are defined once and only one we have 1341 // a complete key. 1342 // 1343 int count = 0; 1344 int [] fieldCnt = new int[m_descriptor.m_fields.size()]; 1345 for (FieldDescriptor fd : m_descriptor.m_fields) 1346 { 1347 fieldCnt[count] = 0; 1348 for (FieldEntry fe : m_entries) 1349 { 1350 if (fd.m_name.equals(fe.m_name)) 1351 { 1352 fieldCnt[count] += 1; 1353 } 1354 } 1355 count += 1; 1356 } 1357 m_hasKeyCoverage = true; 1358 for (int i = 0; i < count; i++) 1359 { 1360 if (fieldCnt[i] != 1) 1361 { 1362 m_hasKeyCoverage = false; 1363 break; 1364 } 1365 } 1366 } 1367 1368 // 1369 // If key coverage doesn't exist, make sure ordered query 1370 // isn't malformed. 1371 // 1372 private void validateOrderedKey() 1373 throws KeyMalformedQueryError 1374 { 1375 assert( !m_hasKeyCoverage ); 1376 1377 String firstField; 1378 int numKeys = 0; 1379 1380 firstField = m_descriptor.m_fields.get(0).m_name; 1381 1382 for (FieldEntry fe : m_entries) 1383 { 1384 if (!fe.m_name.equals(firstField) && numKeys == 0) 1385 { 1386 throw new KeyMalformedQueryError( 1387 "Range queries must use the '" + 1388 firstField + 1389 "' field as the first entry"); 1390 } 1391 if (fe.m_op == KeyComparisonOperator.NEQ && 1392 numKeys == 0) 1393 { 1394 throw new KeyMalformedQueryError( 1395 "Illegal operator != in range query"); 1396 } 1397 numKeys += 1; 1398 } 1399 } 1400 1401 private void validateMinMaxQuery(CompiledQuery query) 1402 throws KeyMalformedQueryError 1403 { 1404 if (m_entries != null) 1405 { 1406 for (FieldEntry fe : m_entries) 1407 { 1408 if (fe.m_op != KeyComparisonOperator.EQ && 1409 fe.m_op != KeyComparisonOperator.GTE && 1410 fe.m_op != KeyComparisonOperator.LTE) 1411 { 1412 throw new KeyMalformedQueryError( 1413 "Illegal operator" + getComparisonOp(fe.m_op) + 1414 "used in query \"" + this + "\""); 1415 } 1416 } 1417 } 1418 if (query.m_filters != null) 1419 { 1420 throw new KeyMalformedQueryError( 1421 "filter present on query \"" + this + "\""); 1422 } 1423 } 1424 1425 private void validateExecution() 1426 throws KeyIncompleteError 1427 { 1428 if (m_query == null) 1429 { 1430 throw new KeyIncompleteError("No query has been defined"); 1431 } 1432 if (m_entries == null) 1433 { 1434 throw new KeyIncompleteError("No fields have been defined"); 1435 } 1436 1437 // We should have passed all audits here 1438 assert( m_hasKeyCoverage || m_descriptor.m_ordered ); 1439 } 1440 1441 private void validateOrdered() 1442 throws KeyIllegalKeyTypeError 1443 { 1444 if (m_descriptor.m_ordered == false) 1445 { 1446 throw new KeyIllegalKeyTypeError( 1447 "Key is not ordered"); 1448 } 1449 } 1450 1451 private CompiledQuery compileSimpleQuery() 1452 { 1453 assert( m_hasKeyCoverage == true ); 1454 1455 CompiledQuery query = new CompiledQuery(); 1456 1457 KeyInfo keyInfo = new KeyInfo(); 1458 1459 // 1460 // build key data based on field order 1461 // 1462 for (FieldDescriptor fd : m_descriptor.m_fields) 1463 { 1464 for (FieldEntry fe : m_entries) 1465 { 1466 if (fd.m_name.equals(fe.m_name)) 1467 { 1468 keyInfo.addKeyData(fe.m_value); 1469 break; 1470 } 1471 } 1472 } 1473 1474 query.addKeyInfo(keyInfo); 1475 1476 return query; 1477 } 1478 1479 private CompiledQuery compileOrderedQuery(CompileFilter filter) 1480 { 1481 assert( m_descriptor.m_ordered == true ); 1482 1483 CompiledQuery query = new CompiledQuery(); 1484 1485 // 1486 // Build first range. This is either a multi-part key 1487 // defined using == clauses, or a one field key using 1488 // another comparison operator. 1489 // 1490 String firstField = m_descriptor.m_fields.get(0).m_name; 1491 Iterator<FieldEntry> iter = m_entries.iterator(); 1492 1493 assert( iter.hasNext() ); 1494 FieldEntry fe = iter.next(); 1495 1496 assert( firstField.equals(fe.m_name) ); 1497 assert( fe.m_op != KeyComparisonOperator.NEQ ); 1498 KeyComparisonOperator firstOp = fe.m_op; 1499 1500 KeyInfo keyInfo = new KeyInfo(mapComparisonOp(fe.m_op)); 1501 1502 if (fe.m_op == KeyComparisonOperator.EQ) 1503 { 1504 // 1505 // Build the key based on the number of == operators. 1506 // 1507 createEqualsKey(keyInfo, filter); 1508 1509 // 1510 // Move the iterator to the next field based on 1511 // the key depth of the built key. 1512 // 1513 assert( keyInfo.m_keyDepth > 0 ); 1514 int keyDepth = keyInfo.m_keyDepth; 1515 1516 while (keyDepth > 0) 1517 { 1518 fe = iter.hasNext() ? iter.next() : null; 1519 keyDepth--; 1520 } 1521 } 1522 else 1523 { 1524 keyInfo.addKeyData(fe.m_value); 1525 fe = iter.hasNext() ? iter.next() : null; 1526 } 1527 query.addRange(keyInfo); 1528 1529 // 1530 // The field entry is now positioned to the next field. 1531 // Determine if we have a range. 1532 // 1533 if (fe != null && firstField.equals(fe.m_name) && 1534 isRange(firstOp, fe.m_op)) 1535 { 1536 keyInfo = new KeyInfo(mapComparisonOp(fe.m_op)); 1537 keyInfo.addKeyData(fe.m_value); 1538 query.addRange(keyInfo); 1539 fe = iter.hasNext() ? iter.next() : null; 1540 } 1541 1542 // 1543 // The rest are filters 1544 // 1545 while (fe != null) 1546 { 1547 query.addFilter(createFilterKey(fe)); 1548 fe = iter.hasNext() ? iter.next() : null; 1549 } 1550 1551 return query; 1552 } 1553 1554 private CompiledQuery compileQuery() 1555 { 1556 if (m_hasKeyCoverage) 1557 { 1558 return compileSimpleQuery(); 1559 } 1560 return compileOrderedQuery(CompileFilter.FILTER_LTEGTE); 1561 } 1562 1563 private void createEqualsKey(KeyInfo keyInfo, CompileFilter filter) 1564 { 1565 // 1566 // Normally, a range query is of only one depth; that is, a 1567 // query that does: 1568 // 1569 // part1 > value 1570 // 1571 // will position the start iterator using the first field 1572 // of a key. When multiple fields use ==, we can optimize 1573 // the position by specifying all the fields instead of 1574 // setting the first one, and filtering on the rest. As 1575 // an example: 1576 // 1577 // part1 == v1 && part2 == v2 1578 // 1579 // can be optimized by defining both part1 and part2 in 1580 // the key, and adjusting the depth so the runtime knows 1581 // to look at both of them when positioning the iterator. 1582 // 1583 // The code below iterates over both the FieldDescriptor 1584 // and FieldEntry, and it continues to build a temp list 1585 // of field entries until the field names don't match, or 1586 // an == is not seen. 1587 // 1588 // The runtime supports positioning of >= and <=, so we also 1589 // allow one of these. But once one is ecountered, the processing 1590 // of the fields terminates, any subsequent expressions are filtered. 1591 // 1592 Iterator<FieldDescriptor> fdIter = 1593 m_descriptor.m_fields.iterator(); 1594 Iterator<FieldEntry> feIter = m_entries.iterator(); 1595 ArrayList<FieldEntry> entries = new ArrayList<FieldEntry>(); 1596 1597 int lastOp = keyInfo.m_rop; 1598 1599 while (feIter.hasNext() && fdIter.hasNext()) 1600 { 1601 FieldDescriptor fd = fdIter.next(); 1602 FieldEntry fe = feIter.next(); 1603 1604 if (filter == CompileFilter.FILTER_LTEGTE) 1605 { 1606 if (fd.m_name.equals(fe.m_name) && 1607 fe.m_op == KeyComparisonOperator.EQ) 1608 { 1609 entries.add(fe); 1610 } 1611 else 1612 { 1613 break; 1614 } 1615 } 1616 else 1617 { 1618 assert( filter == CompileFilter.FILTER_NONE ); 1619 if (fd.m_name.equals(fe.m_name) && 1620 (fe.m_op == KeyComparisonOperator.EQ || 1621 fe.m_op == KeyComparisonOperator.GTE || 1622 fe.m_op == KeyComparisonOperator.LTE)) 1623 { 1624 entries.add(fe); 1625 lastOp = mapComparisonOp(fe.m_op); 1626 1627 if (fe.m_op == KeyComparisonOperator.GTE || 1628 fe.m_op == KeyComparisonOperator.LTE) 1629 { 1630 break; 1631 } 1632 } 1633 else 1634 { 1635 break; 1636 } 1637 } 1638 } 1639 1640 // 1641 // Save the last op, which the runtime uses to position the key. 1642 // 1643 keyInfo.m_rop = lastOp; 1644 1645 // 1646 // Using the temp list, build the actual key 1647 // 1648 keyInfo.m_keyDepth = 0; 1649 for (FieldEntry fe : entries) 1650 { 1651 keyInfo.addKeyData(fe.m_value); 1652 keyInfo.m_keyDepth += 1; 1653 } 1654 assert( keyInfo.m_keyDepth > 0 ); 1655 } 1656 1657 private boolean isRange( 1658 KeyComparisonOperator rop1, 1659 KeyComparisonOperator rop2) 1660 { 1661 // 1662 // See if the operators form a "range" of values. 1663 // 1664 if (rop1 == KeyComparisonOperator.GTE || 1665 rop1 == KeyComparisonOperator.GT) 1666 { 1667 if (rop2 == KeyComparisonOperator.LTE || 1668 rop2 == KeyComparisonOperator.LT) 1669 { 1670 return true; 1671 } 1672 } 1673 if (rop2 == KeyComparisonOperator.GTE || 1674 rop2 == KeyComparisonOperator.GT) 1675 { 1676 if (rop1 == KeyComparisonOperator.LTE || 1677 rop1 == KeyComparisonOperator.LT) 1678 { 1679 return true; 1680 } 1681 } 1682 return false; 1683 } 1684 1685 private KeyInfo createFilterKey(FieldEntry fe) 1686 { 1687 // 1688 // Key filters require a complete key with empty field 1689 // values up to the filtered key field. The runtime uses 1690 // keyDepth to determine which field slot to look at. 1691 // 1692 int keyDepth = 0; 1693 int pos = 0; 1694 for (FieldDescriptor fd : m_descriptor.m_fields) 1695 { 1696 if (fd.m_name.equals(fe.m_name)) 1697 { 1698 break; 1699 } 1700 pos += getKeyOffset(fd.getTypeCode()); 1701 keyDepth++; 1702 } 1703 // 1704 // The filter operator is the opposite of the field 1705 // operator (i.e. to find all the EQ keys, we filter on 1706 // all those that are NEQ). 1707 // 1708 KeyComparisonOperator filterOp = getFilterOp(fe.m_op); 1709 KeyInfo keyInfo = new KeyInfo(mapComparisonOp(filterOp)); 1710 1711 // 1712 // Allocate all the data and position it to the field we 1713 // need to set. We add a null byte in a loop instead of 1714 // the position() call to insure that the contents of the 1715 // preceding key data is zero. 1716 // 1717 while (pos > 0) 1718 { 1719 keyInfo.addKeyData((byte)0); 1720 pos--; 1721 } 1722 keyInfo.addKeyData(fe.m_value); 1723 keyInfo.m_keyDepth = keyDepth; 1724 1725 return keyInfo; 1726 } 1727 1728 private KeyComparisonOperator getFilterOp(KeyComparisonOperator op) 1729 { 1730 KeyComparisonOperator filterOp; 1731 1732 if (op == KeyComparisonOperator.GTE) 1733 { 1734 filterOp = KeyComparisonOperator.LT; 1735 } 1736 else if (op == KeyComparisonOperator.GT) 1737 { 1738 filterOp = KeyComparisonOperator.LTE; 1739 } 1740 else if (op == KeyComparisonOperator.LTE) 1741 { 1742 filterOp = KeyComparisonOperator.GT; 1743 } 1744 else if (op == KeyComparisonOperator.LT) 1745 { 1746 filterOp = KeyComparisonOperator.GTE; 1747 } 1748 else if (op == KeyComparisonOperator.NEQ) 1749 { 1750 filterOp = KeyComparisonOperator.EQ; 1751 } 1752 else 1753 { 1754 assert( op == KeyComparisonOperator.EQ ); 1755 filterOp = KeyComparisonOperator.NEQ; 1756 } 1757 return filterOp; 1758 } 1759 1760 private int mapOrderBy(KeyOrderedBy orderBy) 1761 { 1762 return (orderBy == KeyOrderedBy.ASCENDING) 1763 ? SWRBTreeAscending : SWRBTreeDescending; 1764 } 1765 1766 private int mapObjectLock(LockMode objectLock) 1767 { 1768 switch (objectLock) 1769 { 1770 case NOLOCK: 1771 return KeyOptNoLock; 1772 case READLOCK: 1773 return KeyOptReadLock; 1774 } 1775 assert( objectLock == LockMode.WRITELOCK ); 1776 1777 return KeyOptWriteLock; 1778 } 1779 1780 private int mapComparisonOp(KeyComparisonOperator op) 1781 { 1782 switch (op) 1783 { 1784 case NEQ: 1785 return ObjSrv_NEQ; 1786 case GTE: 1787 return ObjSrv_GTE; 1788 case GT: 1789 return ObjSrv_GT; 1790 case LTE: 1791 return ObjSrv_LTE; 1792 case LT: 1793 return ObjSrv_LT; 1794 } 1795 assert( op == KeyComparisonOperator.EQ ); 1796 1797 return ObjSrv_EQ; 1798 } 1799 1800 private T attachObject(LockMode objectLock, int placeHolder) 1801 { 1802 return _attachObject( 1803 m_descriptor.m_objDomainId, 1804 m_descriptor.m_objTypeId, 1805 m_descriptor.m_keyDomainId, 1806 m_descriptor.m_keyTypeId, 1807 m_query.m_keyInfo1.array(), 1808 placeHolder, 1809 mapObjectLock(objectLock)); 1810 } 1811 1812 private T attachMinimum(CompiledQuery query, LockMode objectLock) 1813 { 1814 return _attachMinimum( 1815 m_descriptor.m_objDomainId, 1816 m_descriptor.m_objTypeId, 1817 m_descriptor.m_keyDomainId, 1818 m_descriptor.m_keyTypeId, 1819 query.m_keyInfo1.m_keyDepth, 1820 query.m_keyInfo1.m_rop, 1821 query.m_keyInfo1.array(), 1822 mapObjectLock(objectLock)); 1823 } 1824 1825 private T attachMaximum(CompiledQuery query, LockMode objectLock) 1826 { 1827 return _attachMaximum( 1828 m_descriptor.m_objDomainId, 1829 m_descriptor.m_objTypeId, 1830 m_descriptor.m_keyDomainId, 1831 m_descriptor.m_keyTypeId, 1832 query.m_keyInfo1.m_keyDepth, 1833 query.m_keyInfo1.m_rop, 1834 query.m_keyInfo1.array(), 1835 mapObjectLock(objectLock)); 1836 } 1837 1838 private T createObject(ArrayList<CreateBuffer> createValues) 1839 { 1840 Object [] cvArray = (createValues == null) 1841 ? null : createValues.toArray(); 1842 return _createObject( 1843 m_descriptor.m_objDomainId, 1844 m_descriptor.m_objTypeId, 1845 m_descriptor.m_keyDomainId, 1846 m_descriptor.m_keyTypeId, 1847 m_query.m_keyInfo1.array(), 1848 cvArray); 1849 } 1850 1851 private native boolean _getKeyDescriptor(KeyDescriptor descriptor); 1852 private native T _attachObject( 1853 int objDomainId, 1854 int objTypeId, 1855 int keyDomainId, 1856 int keyTypeId, 1857 byte [] keyData, 1858 int placeHolder, 1859 int objLock); 1860 private native T _attachMinimum( 1861 int objDomainId, 1862 int objTypeId, 1863 int keyDomainId, 1864 int keyTypeId, 1865 int keyDepth, 1866 int rop, 1867 byte [] keyData, 1868 int objLock); 1869 private native T _attachMaximum( 1870 int objDomainId, 1871 int objTypeId, 1872 int keyDomainId, 1873 int keyTypeId, 1874 int keyDepth, 1875 int rop, 1876 byte [] keyData, 1877 int objLock); 1878 private native T _createObject( 1879 int objDomainId, 1880 int objTypeId, 1881 int keyDomainId, 1882 int keyTypeId, 1883 byte [] keyData, 1884 Object [] createValues); 1885}