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