Package com.mobixess.jodb.core.query

Source Code of com.mobixess.jodb.core.query.QueryNode

/*
Copyright (C) 2007  Mobixess Inc. http://www.java-objects-database.com

This file is part of the JODB (Java Objects Database) open source project.

JODB is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation.

JODB is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package com.mobixess.jodb.core.query;

import java.io.IOException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;

import com.mobixess.jodb.core.IllegalClassTypeException;
import com.mobixess.jodb.core.JODBConfig;
import com.mobixess.jodb.core.JodbIOException;
import com.mobixess.jodb.core.JODBConstants.COMPARE_RESULT;
import com.mobixess.jodb.core.index.IndexDataIterator;
import com.mobixess.jodb.core.index.JODBIndexingAgent;
import com.mobixess.jodb.core.index.JODBIndexingRootAgent;
import com.mobixess.jodb.core.io.IOBase;
import com.mobixess.jodb.core.io.IOTicket;
import com.mobixess.jodb.core.io.JODBOperationContext;
import com.mobixess.jodb.core.io.ObjectDataContainer;
import com.mobixess.jodb.core.io.ObjectDataContainer.FIELD_CATEGORIES;
import com.mobixess.jodb.core.io.ObjectDataContainer.FieldRecord;
import com.mobixess.jodb.core.io.ObjectDataContainer.FieldsIterator;
import com.mobixess.jodb.core.plugin.IClassProcessor;
import com.mobixess.jodb.core.plugin.JODBPluginRegistry;
import com.mobixess.jodb.core.query.SortDataCache.SortNodeRecord;
import com.mobixess.jodb.core.transaction.JODBSession;
import com.mobixess.jodb.core.transaction.TransactionUtils;
import com.mobixess.jodb.core.transaction.JODBSession.ClassDescriptor;
import com.mobixess.jodb.core.transaction.JODBSession.FieldAndIDRecord;
import com.mobixess.jodb.core.transaction.TransactionUtils.DataContainersCache;
//import com.mobixess.jodb.query.api.Evaluation;

import com.mobixess.jodb.query.api.ObjectSet;
import com.mobixess.jodb.soda.api.Constraint;
import com.mobixess.jodb.soda.api.Constraints;
import com.mobixess.jodb.soda.api.Evaluation;
import com.mobixess.jodb.soda.api.Query;
import com.mobixess.jodb.util.ArrayUtils;
import com.mobixess.jodb.util.LongVector;
import com.mobixess.jodb.util.PrimitiveJavaTypesUtil;
import com.mobixess.jodb.util.PrimitiveJavaTypesUtil.PRIMITIVES_ENUMERATION;

@SuppressWarnings("unchecked")
public class QueryNode implements Query, Serializable{
   
    /**
     *
     */
    private static final long serialVersionUID = 1L;
   
    private String _name;
    private transient JODBSession _session;
    private Hashtable< String, QueryNode > _descendants = new Hashtable<String, QueryNode>();//TODO HashMap???
    //private static enum CONSTRAINT_SUBJECT{CLASS_TYPE, EXAMPLE_OBJECT, COMPARISON_OBJECT, EVALUATION};
    private static enum QUERY_SORTING_TYPE{NONE,ASCENDING,DESCENDING};
    private static enum CONSTRAINT_EVALUATION_STATUS{UNKNOWN, ACCEPTED, REJECTED, EXCLUDED};
    private static enum CONSTRAINT_TYPE{CONTAINS,EQUAL,GREATER,SMALLER,NOT,LIKE,IDENTITY};
    private ConstraintsImpl _constraints = new ConstraintsImpl();
    private QueryNode _masterNode;
    private int _masterNodeSortCounter;
    private static HashSet<Object> _defaultByExampleIgnore;
   
    private transient ThreadLocal<ThreadLocalAuxDataHolder> _threadLocalAuxData;
   
    static{
        _defaultByExampleIgnore = new HashSet<Object>();
        PRIMITIVES_ENUMERATION[] primitivesEnum = PRIMITIVES_ENUMERATION.values();
        _defaultByExampleIgnore.add(null);
        for (int i = 0; i < primitivesEnum.length; i++) {
            try {
                Object wrapper = PrimitiveJavaTypesUtil.getDefaultWrapperInstance(primitivesEnum[i]);
                _defaultByExampleIgnore.add(wrapper);
            } catch (JodbIOException e) {
                throw new Error(e);
            }
        }
    }
   
    public QueryNode() {
        initThreadLocalData();
    }
   
    private void initThreadLocalData(){
        _threadLocalAuxData = new ThreadLocal<ThreadLocalAuxDataHolder>() {
            @Override
            protected ThreadLocalAuxDataHolder initialValue()
            {
                return new ThreadLocalAuxDataHolder();
            }
        };
    }
   
    public QueryNode(String name, JODBSession session, QueryNode masterNode) {
        this();
        _name = name;
        _session = session;
        setMasterNode(masterNode);
    }
   
    public QueryNode(Object pattern, Collection defaultIgnoreValues, JODBSession session, QueryNode masterNode) {
        this();
        _name = "";
        _session = session;
        assembleForPattern(pattern, defaultIgnoreValues);
        setMasterNode(masterNode);
    }
   
    public Object readResolve() throws ObjectStreamException{
        initThreadLocalData();
        return this;
    }

   
    private void setMasterNode(QueryNode masterNode){
        if(masterNode == null){
            _masterNode = this;
        }else{
            _masterNode = masterNode;
        }   
    }
   
    public void setSession(JODBSession session) {
        _session = session;
        _constraints.updateSession(session);
        Iterator<QueryNode> iterator = _descendants.values().iterator();
        while (iterator.hasNext()) {
            QueryNode descendant = iterator.next();
            descendant.setSession(session);
        }
    }
   
    public JODBSession getSession() {
        return _session;
    }

    public Constraint constrain(Object constraint) {
        return _constraints.addConsraint(constraint);
    }

    public Constraints constraints() {
        return _constraints;
    }

    public Query descend(String fieldName) {
        synchronized (_descendants) {
            QueryNode descendant = _descendants.get(fieldName);
            if (descendant == null) {
                descendant = new QueryNode(fieldName, _session, _masterNode);
            }
            _descendants.put(fieldName, descendant);
            return descendant;
        }       
    }
   
    public int getNextMasterNodeSortCounter() {
        return _masterNodeSortCounter++;
    }

    public ObjectSet execute() throws IOException, IllegalClassTypeException {
        IOBase base = _session.getBase();
        return base.executeQuery(this);
    }
   
    public JODBQueryList runQuery() throws IOException, IllegalClassTypeException{
        return runQuery(null,null);
    }
   

    public JODBQueryList runQuery(LongVector excludedObjects, LongVector dynamicLongArray) throws IOException, IllegalClassTypeException{
        IOBase base = _session.getBase();
        IOTicket ticket = base.getIOTicket(true, false);
        SortDataCache sortDataCache = new SortDataCache();
        initSortDataCache(sortDataCache, new StringBuffer());
        if(sortDataCache.getSortNodesCacheSize()>0){
            sortDataCache.setValuesAccumulationMode();
        }else{
            sortDataCache.clearAll();
            sortDataCache = null;
        }
        JODBOperationContext context = new JODBOperationContext(_session,ticket,sortDataCache,null,null,excludedObjects,true);
        IndexDataIterator indexIterator = null;
        boolean skipConventionalSorting = false;

        FieldRecord indexDataIteratorFieldRecord = null;//used for iteraion through indexed data
        QueryNode indexedNode = null;
        TypeConstraint typeConstraint = null;
        try{
           
            Vector<ConstraintBase> vectorOfConstraints = _constraints._constraints;
            for (int i = 0; i < vectorOfConstraints.size(); i++) {
                ConstraintBase nextCandidate = vectorOfConstraints.elementAt(i);
                if(nextCandidate instanceof TypeConstraint){
                    if(typeConstraint == null){
                        typeConstraint = (TypeConstraint) nextCandidate;
                    }else{
                        typeConstraint = null;//multiple type constraints
                        break;
                    }
                }
            }
           
            if(typeConstraint != null){
                //boolean useIndexDataFromIterator = false;
                JODBIndexingRootAgent indexingRootAgent = _session.getIndexingRootAgent();
                ClassDescriptor classDescriptor = _session.getDescriptorForClass((Class)typeConstraint.getObject());
                JODBIndexingAgent indexingAgent = null;
                if(sortDataCache!=null){
                    //lookup indexing data to optimize query
                    SortNodeRecord[] sortRecords = sortDataCache.getSortNodes();
                    int fieldId = classDescriptor.getFieldIDForName(sortRecords[0]._fullPath);
                    if(fieldId!=-1){
                        indexingAgent = indexingRootAgent.getIndexingAgent(fieldId, base);
                        if(indexingAgent!=null){
                            indexIterator = indexingAgent.getIndexIterator(sortRecords[0]._orderAscending);
                            indexedNode = _descendants.get(sortRecords[0]._fullPath);
                            skipConventionalSorting = sortRecords.length == 1;
                        }
                    }
                }
                if(indexIterator == null){
                    //search first index
                    Iterator<String> descendants = _descendants.keySet().iterator();
                    while (descendants.hasNext() && indexIterator == null) {
                        String next = descendants.next();
                        Field field = classDescriptor.getFieldForName(next);
                        if(field==null){
                            continue;
                        }
                        indexingAgent = indexingRootAgent.getIndexingAgent(field, base);
                        if(indexingAgent!=null){
                            indexIterator = indexingAgent.getIndexIterator(true);
                            indexedNode = _descendants.get(next);
                        }
                    }
                }
                if(indexingAgent!=null && indexedNode != null){
                    Field field = classDescriptor.getFieldForID(indexingAgent.getFieldId(), null);
                    Class fieldType = field.getType();                       
                    if(fieldType.isPrimitive()){
                        indexDataIteratorFieldRecord = new FieldRecord();
                        indexDataIteratorFieldRecord._fieldID = indexingAgent.getFieldId();
                        indexDataIteratorFieldRecord._category = FIELD_CATEGORIES.PRIMITIVE;
                        indexDataIteratorFieldRecord._fieldTypeID = base.getClassTypeSubstitutionID(fieldType.getName());
                    }
                }
            }
            if(indexIterator==null){
                indexIterator = new LArrayIndexIterator(base.getForAllObjects(ticket));
            }

            LArrayChunkedBuffer acceptedIds = new LArrayChunkedBuffer();

            while (indexIterator.hasNext()) {
                resetStateOfConstraints();
                CONSTRAINT_EVALUATION_STATUS status = CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
                long nextObjectId;
                if(indexDataIteratorFieldRecord!=null){
                    indexDataIteratorFieldRecord._primitiveRawDataBuffer.clear();
                    nextObjectId = indexIterator.next(indexDataIteratorFieldRecord._primitiveRawDataBuffer);
                    if(excludedObjects!=null && excludedObjects.binarySearch(nextObjectId)>=0){
                        continue;
                    }
                    if(_session.getObjectFromCache(nextObjectId) == null){
                        //do not analize active objects
                        indexDataIteratorFieldRecord._primitiveRawDataBuffer.flip();
                        if(sortDataCache!=null){
                            sortDataCache.setCandidateID(nextObjectId);
                        }
                        indexedNode.analize(-1, indexDataIteratorFieldRecord, context);
                        typeConstraint.setStatus(CONSTRAINT_EVALUATION_STATUS.ACCEPTED);
                        _constraints.markExistanceConstrantAsAccepted();
                        indexedNode._constraints.markExistanceConstrantAsAccepted();
                        status = getCumulativeStatus();
                    }
                }else{
                    nextObjectId = indexIterator.next();
                    if(excludedObjects!=null && excludedObjects.binarySearch(nextObjectId)>=0){
                        continue;
                    }
                }
                if(status == CONSTRAINT_EVALUATION_STATUS.UNKNOWN){
                    if(sortDataCache!=null){
                        sortDataCache.setCandidateID(nextObjectId);
                    }
                    status = analize(nextObjectId,context);
                }
                if(status == CONSTRAINT_EVALUATION_STATUS.EXCLUDED){
                    if( !context.isExcludedObjectId(nextObjectId) ){
                        dynamicLongArray.addElement(nextObjectId);
                    }
                    continue;
                }
                if(status == CONSTRAINT_EVALUATION_STATUS.ACCEPTED){
                    if(sortDataCache!=null && JODBConfig.useCacheOnSortOperations()){
                        sortDataCache.acceptCandidate();
                    }
                    acceptedIds.add(nextObjectId);
                }
            }

            long[] resultingOffsets = acceptedIds.toArray();

            if(!skipConventionalSorting){
                handleSortInstructions(sortDataCache, context, resultingOffsets);
            }
            return new SimpleArrayQueryList(resultingOffsets, _session);
        }finally {
            if(sortDataCache!=null){
                sortDataCache.clearAll();
            }
            ticket.close();
        }
    }
   
    private void handleSortInstructions(SortDataCache sortDataCache, JODBOperationContext context, long[] items) throws IOException{
        if(sortDataCache == null){
            return;
        }
        SortingDataProvider sortingDataProvider = new SortingDataProvider(sortDataCache,context,this);
        QueryUtils.quickQuerySort(items, sortingDataProvider, sortDataCache.getSortNodes());
    }
   
    private CONSTRAINT_EVALUATION_STATUS analize(long offset, JODBOperationContext context) throws IOException{
        Object activeObject = _session.getObjectFromCache(offset);
        if(activeObject!=null && !context.isServerMode()){
            return analize(activeObject, null, context);
        }else{
            return analize(offset, null, context);
        }
    }
   
   
    private CONSTRAINT_EVALUATION_STATUS analize(Object object, Field field, JODBOperationContext context) throws IOException{
        _constraints.evaluateActiveObject(object, field, context);
        if(field!=null && field.getType().isPrimitive()){
            return getCumulativeStatus();
        }
        if(field!=null){
            if (object!=null) {
                try {
                    object = field.get(object);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new JodbIOException(e);
                }
            }           
        }else if(object == null){
            return getCumulativeStatus();
        }
        ClassDescriptor classDescriptor;
        classDescriptor = _session.getDescriptorForClass(object!=null?object.getClass():field.getType());
        Iterator<QueryNode> iterator = _descendants.values().iterator();
        while (iterator.hasNext()) {
            QueryNode descendant = iterator.next();
            Field descendantField = classDescriptor.getFieldForName(descendant._name);
            if (descendantField != null) {
                descendant.analize(object, descendantField, context);
            }
        }
        return getCumulativeStatus();
    }

    private CONSTRAINT_EVALUATION_STATUS analize(long objectOffset, FieldRecord fieldRecord, JODBOperationContext context) throws IOException{
        if(context.isServerMode() && context.isExcludedObjectId(objectOffset)){
            _constraints.setStatus(CONSTRAINT_EVALUATION_STATUS.EXCLUDED);
            return CONSTRAINT_EVALUATION_STATUS.EXCLUDED;
        }
        ClassDescriptor classDescriptor = null;
        if( fieldRecord!=null ){
            try {
                classDescriptor = _session.getDescriptorForClass(fieldRecord._fieldTypeID);
            } catch (Exception e) {
                e.printStackTrace();
                throw new JodbIOException(e);
            }
            if(fieldRecord._category == FIELD_CATEGORIES.PRIMITIVE){
                _constraints.evaluatePersistentCopy(classDescriptor, null, fieldRecord, context);
                return getCumulativeStatus();
            }
            objectOffset = fieldRecord._objectOffset;
        }else{
            if(objectOffset <= 0){
                throw new JodbIOException("illegal query state");
            }
        }

        if(objectOffset == 0){
            _constraints.evaluatePersistentCopy(classDescriptor, null, null, context);
            return getCumulativeStatus();
        }
        DataContainersCache dataContainersCache = TransactionUtils.getObjectDataContainerCache();
        ObjectDataContainer dataContainer = dataContainersCache.pullObjectDataContainer();
        IOBase base = _session.getBase();
        IOTicket ticket = base.getIOTicket(true, true);
        try {//TODO need handling for arrays
            dataContainer.readObject(ticket.getRandomAccessBuffer(), base, context.getSession(), objectOffset, true);
            return analize(classDescriptor, dataContainer, context);
        } finally {
            TransactionUtils.getObjectDataContainerCache().pushObjectDataContainer(dataContainer);
            ticket.close();
        }
    }
   
    private CONSTRAINT_EVALUATION_STATUS analize(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, JODBOperationContext context) throws IOException{
        FieldsIterator fieldsIterator = dataContainer.getActiveFieldsIterator();
        if(fieldsIterator==null){
            return getCumulativeStatus();
        }
        //int[] hierarchy = dataContainer.getClassHierarchy();
        int typeID = dataContainer.getOriginalClassType();
        try {
            classDescriptor = _session.getDescriptorForClass(typeID);
        } catch (Exception e) {
            e.printStackTrace();
            throw new JodbIOException(e);
        }
        _constraints.evaluatePersistentCopy(classDescriptor, dataContainer, null, context);
        HashMap<String, Field> unProcessedDescendantFields = _threadLocalAuxData.get()._processedFieldsBuffer;
        unProcessedDescendantFields.clear();
        FieldAndIDRecord[] fields = classDescriptor.getAllFields();
        for (int i = 0; i < fields.length; i++) {
            String name = fields[i]._field.getName();
            if( _descendants.containsKey(name)){
                unProcessedDescendantFields.put(name,fields[i]._field);
            }
        }
        FieldRecord record = dataContainer.getRecordCache();
        while (unProcessedDescendantFields.size() > 0 && fieldsIterator.hasNext()) {
            fieldsIterator.next(record,context.getBase(),false);
            Field field = classDescriptor.getFieldForID(record._fieldID, null);
            String name = field.getName();
            QueryNode descendant = _descendants.get(name);
            if(descendant == null){
                continue;
            }
            if(!unProcessedDescendantFields.containsKey(name)){//TODO can only happen if private fields with same name exist 
                continue;
            }
            descendant.analize(0, record, context);
            unProcessedDescendantFields.remove(name);
        }
       

//        TODO commented because iterrator now guarantee iterration through all field
//        Iterator<Field> remainingFields = unProcessedDescendantFields.values().iterator();
//        while(remainingFields.hasNext()){
//            Field field = remainingFields.next();
//            QueryNode descendant = _descendants.get(field.getName());
//            if(descendant == null){
//                continue;//TODO should never happen, print log???
//            }
//            descendant.analize(null,field, context);
//        }
       
        return getCumulativeStatus();
    }
   
    private void assembleForPattern(Object pattern, Collection defaultIgnoreValues){
        ClassDescriptor classDescriptor = _session.getDescriptorForClass(pattern.getClass());
        constrain(pattern.getClass());
        FieldAndIDRecord[] fields = classDescriptor.getAllFields();
        for (int i = 0; i < fields.length; i++) {
            Field descendant = fields[i]._field;
            Object descendantValue;
            try {
                descendantValue = descendant.get(pattern);
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }
            if(defaultIgnoreValues.contains(descendantValue)){
                continue;
            }
            Query descendantQuery = (QueryNode) descend(descendant.getName());
            descendantQuery.constrain(descendantValue);
        }
        return;
    }

    public CONSTRAINT_EVALUATION_STATUS getCumulativeStatus(){
        CONSTRAINT_EVALUATION_STATUS status = _constraints.getCumulativeStatus();
        if(status == CONSTRAINT_EVALUATION_STATUS.REJECTED){
            return status;
        }
        int totalDescendants = _descendants.size();
        int totalAccepted = 0;
        Iterator<QueryNode> descendantsIterator = _descendants.values().iterator();
        while(descendantsIterator.hasNext()){
            CONSTRAINT_EVALUATION_STATUS descStatus = descendantsIterator.next().getCumulativeStatus();
            switch (descStatus) {
            case ACCEPTED:
                totalAccepted++;
                break;
            case REJECTED:
            case EXCLUDED:
                return descStatus;
            }
        }
        if(status == CONSTRAINT_EVALUATION_STATUS.ACCEPTED && totalDescendants == totalAccepted ){
            return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
        }else{
            return CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
        }
    }
   
    public void markAsUnreachable(){
        _constraints.setStatus(CONSTRAINT_EVALUATION_STATUS.REJECTED);
    }

    public Query orderAscending() {
        _constraints.orderAscending();
        return this;
    }

    public Query orderDescending() {
        _constraints.orderDescending();
        return this;
    }
   
    public void resetStateOfConstraints(){
        _constraints.resetStatus();
        Iterator<QueryNode> iterator = _descendants.values().iterator();
        while (iterator.hasNext()) {
            QueryNode descendant = iterator.next();
            descendant.resetStateOfConstraints();
        }
    }
   
    public void refillSortData(long objectID, SortDataCache sortDataCache, JODBOperationContext context) throws IOException{
        sortDataCache.setCandidateID(objectID);
        if(!hasSortInstructions()){
            return;
        }
        readSortData(objectID, sortDataCache, context);
    }
   
    private void readSortData(long objectID, SortDataCache sortDataCache, JODBOperationContext context) throws IOException{
        if(sortDataCache.isValuesAccumulationComplete()){
            return;
        }
        Object activeObject = context.getSession().getObjectFromCache(objectID);
        if(activeObject!=null){
            readSortData(activeObject, null, sortDataCache, context);
            return;
        }
       
        IOBase base = context.getBase();
        DataContainersCache dataContainersCache = TransactionUtils.getObjectDataContainerCache();
        ObjectDataContainer dataContainer = dataContainersCache.pullObjectDataContainer();
        IOTicket ticket = context.getIoTicket();
        try {
            dataContainer.readObject(ticket.getRandomAccessBuffer(), base, context.getSession(), objectID, true);
            readSortData( dataContainer, (FieldRecord)null, sortDataCache, context);
        } finally {
            TransactionUtils.getObjectDataContainerCache().pushObjectDataContainer(dataContainer);
        }       
    }
   
    private void readSortData(Object activeObject, Field field, SortDataCache sortDataCache, JODBOperationContext context) throws JodbIOException{
        activeObject =_constraints.processSortValuesCache(activeObject, field, context);
        if(_descendants.isEmpty() && sortDataCache.isValuesAccumulationComplete()){
            return;
        }
        if(activeObject!=null){
            Enumeration<QueryNode> descendants = _descendants.elements();
            while (descendants.hasMoreElements()) {
                QueryNode descendantQueryNode = descendants.nextElement();
                if(descendantQueryNode.hasSortInstructions()){
                    ClassDescriptor classDescriptor = context.getSession().getDescriptorForClass(activeObject.getClass());
                    Field descendantField = classDescriptor.getFieldForName(descendantQueryNode._name);
                    if(descendantField!=null){
                        descendantQueryNode.readSortData(activeObject, descendantField, sortDataCache, context);
                    }
                }
            }
            return;
        }
    }
   
    private void readSortData(ObjectDataContainer dataContainer, FieldRecord fieldRecord, SortDataCache sortDataCache, JODBOperationContext context) throws IOException{
        _constraints.processSortValuesCache(dataContainer, fieldRecord, context);
        if(_descendants.isEmpty() && sortDataCache.isValuesAccumulationComplete()){
            return;
        }
        if(fieldRecord!=null){
            if(fieldRecord._category == FIELD_CATEGORIES.PRIMITIVE){
                return;
            }
            long nextObjectID = fieldRecord._objectOffset;
            readSortData(nextObjectID, sortDataCache, context);
            return;
        } else {
            FieldsIterator fieldsIterator = dataContainer.getActiveFieldsIterator();
            if(fieldsIterator == null){
                return;//TODO add warning?
            }
            FieldRecord iterratorFieldRecord = dataContainer.getRecordCache();
            IOBase base = context.getBase();
            while(fieldsIterator.hasNext()){
                fieldsIterator.next(iterratorFieldRecord, context.getBase(),false);
                QueryNode descendant = _descendants.get(base.getSimpleFieldNameForID(iterratorFieldRecord._fieldID));
                if(descendant!=null && descendant.hasSortInstructions()){
                    descendant.readSortData(null, iterratorFieldRecord, sortDataCache, context);
                }
                if(sortDataCache.isValuesAccumulationComplete()){
                    return;
                }
            }
        }
    }
   
    private boolean hasSortInstructions(){
        if(_constraints._sortingNodeId!=-1){
            return true;
        }
        return descendantsHaveSortInstructions();
    }
   
    private boolean descendantsHaveSortInstructions(){
        if(_descendants.isEmpty()){
            return false;
        }
        Enumeration<QueryNode> descendants = _descendants.elements();
        while (descendants.hasMoreElements()) {
            QueryNode element = descendants.nextElement();
            if(element.hasSortInstructions()){
                return true;
            }
        }
        return false;
    }
   
   
   
    public void initSortDataCache(SortDataCache sortDataCache, StringBuffer path)
    {
        _constraints.initSortDataCache(sortDataCache,path);
        Iterator<QueryNode> iterator = _descendants.values().iterator();
        int pathLen = path.length();
        while (iterator.hasNext()) {
            QueryNode descendant = iterator.next();
            if(path.length()!=0){
                path.append('.');
            }
            path.append(descendant._name);
            descendant.initSortDataCache(sortDataCache,path);
            path.setLength(pathLen);
        }
    }
   
    private static class ThreadLocalAuxDataHolder{
        private HashMap<String, Field> _processedFieldsBuffer = new HashMap<String, Field>();
    }
   
   
   
    private class ConstraintsImpl extends ConstraintBase implements Constraints, Serializable{
        /**
         *
         */
        private static final long serialVersionUID = 1L;
        Vector<ConstraintBase> _constraints = new Vector<ConstraintBase>();
        QUERY_SORTING_TYPE _sortingType = QUERY_SORTING_TYPE.NONE;
        int _sortingNodeId = -1;
        private boolean _recursiveSatusRequest;
       
       
        public ConstraintsImpl() {
            _constraints.add(new ExistanceConstraint());
        }
       
        @Override
        public void resetStatus()
        {
            int len = _constraints.size();
            for (int i = 0; i < len; i++) {
                ConstraintBase constraint = _constraints.elementAt(i);
                if (constraint == this) {
                    continue;
                }
                constraint.resetStatus();
            }
        }
       
        @Override
        public void setStatus(CONSTRAINT_EVALUATION_STATUS newStatus)
        {
            int len = _constraints.size();
            for (int i = 0; i < len; i++) {
                ConstraintBase constraint = _constraints.elementAt(i);
                if (constraint == this) {
                    continue;
                }
                constraint.setStatus(newStatus);
            }
        }
       
        public void initSortDataCache(SortDataCache sortDataCache, StringBuffer path)
        {
            if(_sortingType!= QUERY_SORTING_TYPE.NONE){
                sortDataCache.addNode(_sortingNodeId,path.toString(), _sortingType ==QUERY_SORTING_TYPE.ASCENDING);
            }
        }
       
        public void markExistanceConstrantAsAccepted(){
            int len = _constraints.size();
            for (int i = 0; i < len; i++) {
                ConstraintBase constraint = _constraints.elementAt(i);
                if (constraint == this) {
                    continue;
                }
                if(constraint instanceof ExistanceConstraint){
                    constraint.setStatus(CONSTRAINT_EVALUATION_STATUS.ACCEPTED);
                }
            }
        }
       
        public ConstraintBase addConsraint(Object constraint){
            ConstraintBase result;
            if(constraint instanceof Class){
                result = new TypeConstraint((Class) constraint);
            }else if(constraint instanceof Evaluation){
                result = new EvaluationCallbackConstraint((Evaluation) constraint);
            }else{
                Class constraintClass = constraint.getClass();
                if(constraint instanceof String || constraint instanceof Enum ||
                        constraintClass.isArray() ||
                        PrimitiveJavaTypesUtil.isPrimitiveWrapper(constraintClass) )
                {
                    result = new ValueComparisonConstraint(constraint);
                }else{
                    result = new QueryByExample(constraint,_defaultByExampleIgnore, _session);
                }
               
            }
            _constraints.add(result);
            return result;
        }
       
        @Override
        public CONSTRAINT_EVALUATION_STATUS getStatus()
        {
            return getCumulativeStatus();
        }
       
        @Override
        public CONSTRAINT_EVALUATION_STATUS getCumulativeStatus()
        {// statis calculated in accordance with AND operation for all contained constraints
            if(_recursiveSatusRequest || _constraints.size() == 0){
                return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
            }
            _recursiveSatusRequest = true;
            try {
                int len = _constraints.size();
                int totalAccepted = 0;
                for (int i = 0; i < len; i++) {
                    ConstraintBase constraint = _constraints.elementAt(i);
                    if (constraint == this) {
                        continue;
                    }
                    if (constraint.getCumulativeStatus() == CONSTRAINT_EVALUATION_STATUS.REJECTED)
                    {
                        return CONSTRAINT_EVALUATION_STATUS.REJECTED;
                    }
                    if (constraint.getCumulativeStatus() == CONSTRAINT_EVALUATION_STATUS.ACCEPTED)
                    {
                        totalAccepted++;
                    }
                }
                if (totalAccepted == len) {
                    return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
                } else {
                    return CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
                }
            } finally {
                _recursiveSatusRequest = false;
            }           
        }
       
        public Constraint[] toArray() {
            throw new RuntimeException("Not Implemented");
            //return null;
        }
       
        public Constraint and(Constraint with) {
            int len = _constraints.size();
            for (int i = 0; i < len; i++) {
                _constraints.elementAt(i).and(with);
            }
            return this;
        }
       
        public Constraint contains() {
            int len = _constraints.size();
            for (int i = 0; i < len; i++) {
                _constraints.elementAt(i).contains();
            }
            return this;
        }
       
        public Constraint equal() {
            int len = _constraints.size();
            for (int i = 0; i < len; i++) {
                _constraints.elementAt(i).equal();
            }
            return this;
        }
       
        public Object getObject() {
            return null;//TODO check correctness
        }
       
        public Constraint greater() {
            int len = _constraints.size();
            for (int i = 0; i < len; i++) {
                _constraints.elementAt(i).greater();
            }
            return this;
        }
       
        public Constraint identity() {
            int len = _constraints.size();
            for (int i = 0; i < len; i++) {
                _constraints.elementAt(i).identity();
            }
            return this;
        }
       
        public Constraint like() {
            int len = _constraints.size();
            for (int i = 0; i < len; i++) {
                _constraints.elementAt(i).like();
            }
            return this;
        }
       
        public Constraint not() {
            int len = _constraints.size();
            for (int i = 0; i < len; i++) {
                _constraints.elementAt(i).not();
            }
            return this;
        }
       
        public Constraint or(Constraint with) {
            int len = _constraints.size();
            for (int i = 0; i < len; i++) {
                _constraints.elementAt(i).or(with);
            }
            return this;
        }
       
        public Constraint smaller() {
            int len = _constraints.size();
            for (int i = 0; i < len; i++) {
                _constraints.elementAt(i).smaller();
            }
            return this;
        }

        @Override
        void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
        {
            int totalConstraints = _constraints.size();
            for (int i = 0; i < totalConstraints; i++) {
                _constraints.elementAt(i).evaluateActiveObject(activeObject, field, context);
            }
            if(JODBConfig.useCacheOnSortOperations()){
                processSortValuesCache(activeObject, field, context);
            }
        }
       
        /**
         *
         * @param activeObject
         * @param field
         * @param context
         * @return active object for descendant analysis - can be result of extraction from 'field', original activeObject or null
         * @throws JodbIOException
         */
        private Object processSortValuesCache(Object activeObject, Field field, JODBOperationContext context) throws JodbIOException{
            if(_sortingNodeId==-1){
                return activeObject;
            }
            if(field!=null){
                Class type = field.getType();
                if (type == String.class || type == Enum.class || type.isPrimitive() || PrimitiveJavaTypesUtil.isPrimitiveWrapper(type)) {
                    try {
                        activeObject = field.get(activeObject);
                    } catch (Exception e) {
                        throw new JodbIOException(e);
                    }
                }else{
                    activeObject = null;
                }
            }
           
            if(activeObject!=null && (activeObject instanceof String || activeObject instanceof Enum || PrimitiveJavaTypesUtil.isPrimitiveWrapper(activeObject.getClass()))){
                SortDataCache sortDataCache = context.getSortDataCache();
                if(sortDataCache!=null){
                    sortDataCache.addSortValue(_sortingNodeId, activeObject);
                }
                return null;
            }
            return activeObject;
        }

        @Override
        void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord primitiveRecord, JODBOperationContext context) throws IOException
        {
            int totalConstraints = _constraints.size();
            for (int i = 0; i < totalConstraints; i++) {
                _constraints.elementAt(i).evaluatePersistentCopy(classDescriptor, dataContainer, primitiveRecord, context);
                if(dataContainer!=null && i < totalConstraints){
                    FieldsIterator fieldsIterator = dataContainer.getActiveFieldsIterator();
                    if(fieldsIterator != null){
                        fieldsIterator.reset();
                    }
                }
            }
            if(JODBConfig.useCacheOnSortOperations()){
                processSortValuesCache(dataContainer, primitiveRecord, context);
            }
        }
       
        @Override
        void updateSession(JODBSession session)
        {
            int totalConstraints = _constraints.size();
            for (int i = 0; i < totalConstraints; i++) {
                _constraints.elementAt(i).updateSession(session);
            }
        }
       
        private void processSortValuesCache(ObjectDataContainer dataContainer, FieldRecord primitiveRecord, JODBOperationContext context) throws IOException{
            if(_sortingNodeId==-1){
                return;
            }
            if(primitiveRecord!=null){
                SortDataCache sortDataCache = context.getSortDataCache();
                if(primitiveRecord._category == FIELD_CATEGORIES.PRIMITIVE){
                    if(sortDataCache!=null){
                        PRIMITIVES_ENUMERATION fieldTypeEnum = PrimitiveJavaTypesUtil.getEnumeratedType(primitiveRecord._fieldTypeID, context.getBase());
                        sortDataCache.addSortValue(_sortingNodeId, PrimitiveJavaTypesUtil.getAsWrappedPrimitive(fieldTypeEnum, primitiveRecord._primitiveRawDataBuffer));
                    }
                }else if(primitiveRecord._fieldTypeName.equals(String.class.getName())){//TODO check for enum?
                    Object value = TransactionUtils.launchObject(context.getSession(), primitiveRecord._objectOffset , null, 1);
                    sortDataCache.addSortValue(_sortingNodeId, value);
                }
                return;
            }
            if(dataContainer!=null){
                Class persistentObjectClass;
                try {
                    persistentObjectClass = context.getSession().resolveClassForID(dataContainer.getOriginalClassType());
                } catch (ClassNotFoundException e) {
                    //TODO debug output???
                    throw new JodbIOException(e);
                }
               
                if(persistentObjectClass==String.class || Enum.class.isAssignableFrom(persistentObjectClass)){
                    SortDataCache sortDataCache = context.getSortDataCache();
                    if(sortDataCache!=null){
                        Object value = TransactionUtils.launchObject(context.getSession(), dataContainer.getOffset(), null, 1);
                        if(value!=null && (value instanceof String || value instanceof Enum)){
                            sortDataCache.addSortValue(_sortingNodeId,value);
                        }else{
                            System.err.println(" Warning internal state mismatch");//TODO add log
                        }
                    }
                }                   
            }
        }

        public void orderAscending() {
            _sortingType = QUERY_SORTING_TYPE.ASCENDING;
            setSortConstraintIndex();
        }

        public void orderDescending() {
            _sortingType = QUERY_SORTING_TYPE.DESCENDING;
            setSortConstraintIndex();
        }
       
        private void setSortConstraintIndex(){
            if(_sortingNodeId == -1){
                _sortingNodeId = _masterNode.getNextMasterNodeSortCounter();
            }
        }
    }
   
    private static class ConstraintLink extends ConstraintBase{
        /**
         *
         */
        private static final long serialVersionUID = 1L;
        private boolean _linkTypeIsOr;
        private ConstraintBase _constraint1;
        private ConstraintBase _constraint2;
      
       
       
        /**
         * @param linkTypeIsOr
         * @param constraint1
         * @param constraint2
         */
        public ConstraintLink(boolean linkTypeIsOr, ConstraintBase constraint1, ConstraintBase constraint2) {
            _linkTypeIsOr = linkTypeIsOr;
            _constraint1 = constraint1;
            _constraint2 = constraint2;
        }



        @Override
        public CONSTRAINT_EVALUATION_STATUS getCumulativeStatus()
        {
            CONSTRAINT_EVALUATION_STATUS status1 = _constraint1.getStatus();
            CONSTRAINT_EVALUATION_STATUS status2 = _constraint2.getStatus();
            if(_linkTypeIsOr){
                if(status1 == CONSTRAINT_EVALUATION_STATUS.ACCEPTED || status2 == CONSTRAINT_EVALUATION_STATUS.ACCEPTED ){
                    return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
                }
                if(status1 == CONSTRAINT_EVALUATION_STATUS.UNKNOWN || status2 == CONSTRAINT_EVALUATION_STATUS.UNKNOWN ){
                    return CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
                }
                return CONSTRAINT_EVALUATION_STATUS.REJECTED;
            }else{
                if(status1 == CONSTRAINT_EVALUATION_STATUS.REJECTED || status2 == CONSTRAINT_EVALUATION_STATUS.REJECTED ){
                    return CONSTRAINT_EVALUATION_STATUS.REJECTED;
                }
                if(status1 == CONSTRAINT_EVALUATION_STATUS.UNKNOWN || status2 == CONSTRAINT_EVALUATION_STATUS.UNKNOWN ){
                    return CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
                }
                return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
            }
        }



        public Constraint contains() {
            return this;
        }



        public Constraint equal() {
            return this;
        }



        public Object getObject() {
            return null;
        }



        public Constraint greater() {
            return this;
        }



        public Constraint identity() {
            return this;
        }



        public Constraint like() {
            return this;
        }



        public Constraint not() {
            return this;
        }



        public Constraint smaller() {
            return this;
        }



        @Override
        void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context)
        {
            throw new RuntimeException("Not Implemented");
            //
        }



        @Override
        void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord primitiveRecord, JODBOperationContext context)
        {
            throw new RuntimeException("Not Implemented");
            //
        }
       
    }

    private class QueryByExample extends ValueComparisonConstraint{
       
        /**
         *
         */
        private static final long serialVersionUID = 1L;
        private QueryNode _queryNode;

        public QueryByExample(Object constraintOrigin, Collection defaultIgnoreValues, JODBSession session) {
            super(null);
            _queryNode = new QueryNode(constraintOrigin,defaultIgnoreValues, session, _masterNode);
        }
       
        @Override
        void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
        {
            _queryNode.analize(activeObject, field, context);
            processEvaluationResult();
        }
       
        @Override
        void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord record, JODBOperationContext context) throws IOException
        {
            _queryNode.analize(classDescriptor, dataContainer, context);
            processEvaluationResult();
        }
       
        private void processEvaluationResult(){
            CONSTRAINT_EVALUATION_STATUS status = _queryNode.getCumulativeStatus();
            switch (_type) {
            case EQUAL:
            case LIKE:
                setStatus(status);
                break;
            case NOT:
                if(status == CONSTRAINT_EVALUATION_STATUS.ACCEPTED){
                    setStatus(CONSTRAINT_EVALUATION_STATUS.REJECTED);
                }else{
                    setStatus(CONSTRAINT_EVALUATION_STATUS.ACCEPTED);
                }
            default:
                setStatus(CONSTRAINT_EVALUATION_STATUS.UNKNOWN);
            }
        }
       
        @Override
        public void resetStatus()
        {
            super.resetStatus();
            _queryNode._constraints.resetStatus();
        }
       
        @Override
        void updateSession(JODBSession session)
        {
            _queryNode.setSession(session);
        }
       
//        @Override
//        public CONSTRAINT_EVALUATION_STATUS getCumulativeStatus()
//        {
//            return _queryNode.getCumulativeStatus();
//        }
//       
//        @Override
//        public CONSTRAINT_EVALUATION_STATUS getStatus()
//        {
//            return getCumulativeStatus();
//        }
       
    }
   
    private static class ValueComparisonConstraint extends ConstraintBase{

        /**
         *
         */
        private static final long serialVersionUID = 1L;
        private Object _constraintOrigin;
        private transient WeakReference<Object> _translatedOrigin = new WeakReference<Object>(null);
        CONSTRAINT_TYPE _type = CONSTRAINT_TYPE.EQUAL;
       
       
       
        /**
         * @param constraintOrigin
         */
        public ValueComparisonConstraint(Object constraintOrigin) {
            super();
            _constraintOrigin = constraintOrigin;
        }

        public Constraint contains() {
            _type=CONSTRAINT_TYPE.CONTAINS;
            return this;
        }

        public Constraint equal() {
            _type=CONSTRAINT_TYPE.EQUAL;
            return this;
        }

        public Object getObject() {
            return _constraintOrigin;
        }

        public Constraint greater() {
            _type=CONSTRAINT_TYPE.GREATER;
            return this;
        }

        public Constraint identity() {
            _type=CONSTRAINT_TYPE.IDENTITY;
            return this;
        }

        public Constraint like() {
            _type=CONSTRAINT_TYPE.LIKE;
            return this;
        }

        public Constraint not() {
            _type=CONSTRAINT_TYPE.NOT;
            return this;
        }
       
        public Constraint smaller() {
            _type=CONSTRAINT_TYPE.SMALLER;
            return this;
        }
       
        Object getTranslatedOrigin() throws IOException{
            Object result = null;
            if(_translatedOrigin!=null){
                result = _translatedOrigin.get();
            }
            if(result == null){
                Class originClass = getObject().getClass();
                if(PrimitiveJavaTypesUtil.isPrimitiveWrapper(originClass)){
                    return getObject();
                }
                IClassProcessor classProcessor = JODBPluginRegistry.getInstance().getClassProcessor(originClass);
                result = classProcessor.translate(getObject());
                _translatedOrigin = new WeakReference(result);
            }
            return result;
        }

        @Override
        void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
        {
            Class originClass = getObject().getClass();
            if(field!= null && field.getType().isPrimitive()){
                COMPARE_RESULT compareResult;
                if(!PrimitiveJavaTypesUtil.isPrimitiveWrapper(originClass)){
                    compareResult = COMPARE_RESULT.UNKNOWN;
                }else{
                    compareResult = PrimitiveJavaTypesUtil.compare(_constraintOrigin, field, activeObject);
                }
                processCompareResult(compareResult);
                return;
            }
            if(field!=null && activeObject!=null){
                try {
                    activeObject = field.get(activeObject);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new JodbIOException(e);
                }
            }
            if(activeObject!=null){
                if(originClass != activeObject.getClass()){
                    processCompareResult(COMPARE_RESULT.UNKNOWN);
                    return;
                }
                IClassProcessor processor = JODBPluginRegistry.getInstance().getClassProcessor(originClass);
                COMPARE_RESULT compareResult = processor.compare(getObject(),activeObject, context, null);
                processCompareResult(compareResult);
                return;
            }
        }
       
        /*package*/ void processCompareResult(COMPARE_RESULT compareResult) throws JodbIOException{
            CONSTRAINT_EVALUATION_STATUS status = getStatusForCompareResult(compareResult, _type);
            setStatus(status);
        }
       
        private CONSTRAINT_EVALUATION_STATUS getStatusForCompareResult(COMPARE_RESULT compareResult, CONSTRAINT_TYPE type ) throws JodbIOException{
            if(compareResult == COMPARE_RESULT.UNKNOWN){
                return CONSTRAINT_EVALUATION_STATUS.REJECTED;
            }
            switch (type) {
            case EQUAL:
            case IDENTITY:
            case LIKE:
                if(compareResult == COMPARE_RESULT.EQUAL){
                    return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
                }else{
                    return CONSTRAINT_EVALUATION_STATUS.REJECTED;
                }
            case GREATER:
                if(compareResult == COMPARE_RESULT.SMALLER){
                    return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
                }else{
                    return CONSTRAINT_EVALUATION_STATUS.REJECTED;
                }
            case SMALLER:
                if(compareResult == COMPARE_RESULT.GREATER){
                    return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
                }else{
                    return CONSTRAINT_EVALUATION_STATUS.REJECTED;
                }
            case NOT:
                if(compareResult != COMPARE_RESULT.EQUAL){
                    return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
                }else{
                    return CONSTRAINT_EVALUATION_STATUS.REJECTED;
                }
            default:
                throw new JodbIOException();
            }
        }

        @Override
        void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord record, JODBOperationContext context) throws IOException
        {
            Class originClass = getObject().getClass();
            if(record!=null && record._category == FIELD_CATEGORIES.PRIMITIVE){
                COMPARE_RESULT compareResult;
                if(!PrimitiveJavaTypesUtil.isPrimitiveWrapper(originClass)){
                    compareResult = COMPARE_RESULT.UNKNOWN;
                }else{
                    PRIMITIVES_ENUMERATION fieldTypeEnum = PrimitiveJavaTypesUtil.getEnumeratedType(record._fieldTypeID, context.getBase());
                    compareResult = PrimitiveJavaTypesUtil.compare(_constraintOrigin, record, fieldTypeEnum);
                }
                processCompareResult(compareResult);
                return;
            }
            if(dataContainer!=null){
                Class persistentObjectClass;
                try {
                    persistentObjectClass = context.getSession().resolveClassForID(dataContainer.getOriginalClassType());
                } catch (ClassNotFoundException e) {
                    //TODO debug output???
                    throw new JodbIOException(e);
                }
                if(originClass!=persistentObjectClass){
                    processCompareResult(COMPARE_RESULT.UNKNOWN);
                    return;
                }
                IClassProcessor processor = JODBPluginRegistry.getInstance().getClassProcessor(originClass);
                if(_type == CONSTRAINT_TYPE.EQUAL || _type == CONSTRAINT_TYPE.NOT){//equals methods can be better optimized
                    boolean equal = processor.equals(getTranslatedOrigin(), dataContainer, context, null);
                    processCompareResult(equal? COMPARE_RESULT.EQUAL : COMPARE_RESULT.SMALLER);
                    return;
                }else{
                    COMPARE_RESULT compareResult = processor.compare(getTranslatedOrigin(), dataContainer, context, null, originClass);
                    processCompareResult(compareResult);
                    return;
                }
               
            }
        }
    }
   
    private static class TypeConstraint extends ValueComparisonConstraint{
       
        /**
         *
         */
        private static final long serialVersionUID = 1L;
        int _constraintClassTypeID = -1;

        public TypeConstraint(Class constraintOrigin) {
            super(constraintOrigin);
        }
        @Override
        void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
        {
            Class constaintClass = (Class) getObject();
            boolean isInstanceOf = false;
            if(field!=null){
                isInstanceOf = field.getType().isAssignableFrom(constaintClass);
                if(!isInstanceOf && activeObject!=null){
                    try {
                        activeObject = field.get(activeObject);
                    } catch (Exception e) {
                        e.printStackTrace();
                        throw new JodbIOException(e);
                    }
                }
            }
            if(!isInstanceOf){
                if( activeObject!=null){
                    isInstanceOf = constaintClass.isInstance(activeObject);
                }else{
                    setStatus(CONSTRAINT_EVALUATION_STATUS.REJECTED);
                    return;
                }
            }

            setStatus(evaluateObject(isInstanceOf, _type ));
        }
       
        @Override
        public void resetStatus()
        {
            _constraintClassTypeID=-1;
        }
       
        private CONSTRAINT_EVALUATION_STATUS evaluateObject(boolean isInstanceOfConstraint, CONSTRAINT_TYPE type) throws JodbIOException{
            switch (type) {
            case EQUAL:
            case IDENTITY:
            case LIKE:
                if(isInstanceOfConstraint ){
                    return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
                }else{
                    return CONSTRAINT_EVALUATION_STATUS.REJECTED;
                }
            case GREATER:
            case SMALLER:
                    return CONSTRAINT_EVALUATION_STATUS.REJECTED;
            case NOT:
                if(!isInstanceOfConstraint ){
                    return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
                }else{
                    return CONSTRAINT_EVALUATION_STATUS.REJECTED;
                }
            default:
                throw new JodbIOException();
            }
        }
       
        @Override
        void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord record, JODBOperationContext context) throws JodbIOException
        {
            setStatus(evaluatePersistentCopyForType(_type, classDescriptor, dataContainer, record, context.getSession()));
        }
       
        CONSTRAINT_EVALUATION_STATUS evaluatePersistentCopyForType(CONSTRAINT_TYPE type, ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord record, JODBSession session) throws JodbIOException
        {
            boolean isInstanceOf;
            if(classDescriptor == null){
                isInstanceOf = false;
            }else{
                String[] hierarchy = classDescriptor.getTypes();
                String className = ((Class)getObject()).getName();
                if(ArrayUtils.indexOf(hierarchy, className)==-1){
                    isInstanceOf = false;
                }else{
                    isInstanceOf = true;
                }
            }
            return evaluateObject(isInstanceOf, type);
        }
       
        public int getConstraintClassTypeID(JODBSession session) throws JodbIOException {
            int result = _constraintClassTypeID;//precaution in case of multi threading
            if(result == -1){
                result = session.getBase().getClassTypeSubstitutionID(((Class)getObject()).getName());
                _constraintClassTypeID = result;
            }
            return result;
        }
    }
   
    /*private class ByExampleConstraint extends ValueComparisonConstraint{

        Field[] _fieldsToIgnore;
       
        public ByExampleConstraint(Object constraintOrigin) {
            super(constraintOrigin);
            Object translatedOrigin = getTranslatedOrigin();
            try {//TODO should have two copies of ignore fields for original object and translated
                ClassDescriptor classDescriptor = _session.getDescriptorForClass(translatedOrigin.getClass());
                Vector<Field> fieldsToIgnore = new Vector<Field>();
                Field[] fields = classDescriptor.getFields();
                for (int i = 0; i < fields.length; i++) {
                    Field field = fields[i];
                    Object val = field.get(translatedOrigin);
                    if(val == null){
                        fieldsToIgnore.add(field);
                        continue;
                    }
                    Class type = field.getType();
                    if(type.isPrimitive()){
                        Object wrapperObj = PrimitiveJavaTypesUtil.getDefaultWrapperInstance(type.getName());
                        if(val.equals( wrapperObj )  ){
                            fieldsToIgnore.add(field);
                            continue;
                        }
                    }
                }
                _fieldsToIgnore = new Field[fieldsToIgnore.size()];
                _fieldsToIgnore = fieldsToIgnore.toArray(_fieldsToIgnore);
            } catch (Exception e) {
                e.printStackTrace();
                _fieldsToIgnore = new Field[0];
                processCompareResult(COMPARE_RESULT.UNKNOWN);
            }
           
        }
       
        @Override
        void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
        {
            if(field!=null && activeObject!=null){
                try {
                    activeObject = field.get(activeObject);
                } catch (Exception e) {
                    throw new IOException(e.getMessage());
                }
            }
            if(activeObject!=null){
                Object byExapleConstraint = getObject();
                if(activeObject.getClass()!=byExapleConstraint.getClass()){
                    processCompareResult(COMPARE_RESULT.GREATER);
                    return;
                }
                IClassProcessor processor = JODBPluginRegistry.getInstance().getClassProcessor(byExapleConstraint.getClass());
                COMPARE_RESULT compare_result = processor.compare(byExapleConstraint, activeObject, context, _fieldsToIgnore);
                processCompareResult(compare_result);
            }
        }
       
        @Override
        void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord record, JODBOperationContext context) throws IOException
        {
            if(record!=null){
                if(record._category == FIELD_CATEGORIES.PRIMITIVE){
                    processCompareResult(COMPARE_RESULT.GREATER);
                    return;
                }
            }
            if(dataContainer!=null){
//                Class originClass = getObject().getClass();
//                Class persistentObjectClass;
//                try {
//                    persistentObjectClass = context.getSession().resolveClassForID(dataContainer.getOriginalClassType());
//                } catch (ClassNotFoundException e) {
//                    //TODO debug output???
//                    throw new IOException(e.getMessage());
//                }
//                if(originClass!=persistentObjectClass){
//                    processCompareResult(COMPARE_RESULT.UNKNOWN);
//                    return;
//                }
               
                Object byExapleConstraint = getObject();
                if(classDescriptor.getType()!=byExapleConstraint.getClass()){
                    processCompareResult(COMPARE_RESULT.GREATER);
                    return;
                }
               
                IClassProcessor processor = JODBPluginRegistry.getInstance().getClassProcessor(byExapleConstraint.getClass());
                if(_type == CONSTRAINT_TYPE.EQUAL || _type == CONSTRAINT_TYPE.NOT){//equals methods can be better optimized
                    boolean equal = processor.equals(getTranslatedOrigin(), dataContainer, context, _fieldsToIgnore);
                    processCompareResult(equal? COMPARE_RESULT.EQUAL : COMPARE_RESULT.SMALLER);
                    return;
                }else{
                    COMPARE_RESULT compareResult = processor.compare(getTranslatedOrigin(), dataContainer, context, _fieldsToIgnore);
                    processCompareResult(compareResult);
                    return;
                }
            }
        }
  
    }*/
   
    private static class EvaluationCallbackConstraint extends ValueComparisonConstraint{
       
        private ThreadLocal<CandidateImpl> _candidateImpl = new ThreadLocal<CandidateImpl>() {
            @Override
            protected CandidateImpl initialValue()
            {
                return new CandidateImpl();
            }
        };

        public EvaluationCallbackConstraint(Evaluation constraintOrigin) {
            super(constraintOrigin);
        }
       
        @Override
        void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
        {
            if(field!=null && activeObject!=null){
                try {
                    activeObject = field.get(activeObject);
                } catch (Exception e) {
                    throw new JodbIOException(e);
                }
            }
            if(activeObject!=null){
                Evaluation evaluation = (Evaluation) getObject();
                CandidateImpl candidateImpl = _candidateImpl.get();
                candidateImpl.init(activeObject);
                evaluation.evaluate(candidateImpl);
                if(candidateImpl.isInclude()){
                    processCompareResult(COMPARE_RESULT.EQUAL);
                }else{
                    processCompareResult(COMPARE_RESULT.SMALLER);
                }
            }
        }
       
        @Override
        void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord record, JODBOperationContext context) throws IOException
        {
            if(record!=null && record._category == FIELD_CATEGORIES.PRIMITIVE){
                PRIMITIVES_ENUMERATION fieldTypeEnum = PrimitiveJavaTypesUtil.getEnumeratedType(record._fieldTypeID, context.getBase());
                Object obj = PrimitiveJavaTypesUtil.getAsWrappedPrimitive(fieldTypeEnum,record._primitiveRawDataBuffer);
                evaluateActiveObject(obj, null, context);
                return;
            }
            if(dataContainer!=null){
                Evaluation evaluation = (Evaluation) getObject();
                int activationDepth = evaluation.getActivationDepth() >= 0 ? evaluation.getActivationDepth() : JODBConfig.getDefaultActivationDepth();
                Object obj = context.getSession().getObjectForOffset(dataContainer.getOffset(), activationDepth);
                evaluateActiveObject(obj, null, context);
                return;
            }
        }
       
    }

   
    /**
     * Constraint to ensure that field actually exists
     *
     * @author Mobixess
     *
     */
    private static class ExistanceConstraint extends ConstraintBase{

        /**
         *
         */
        private static final long serialVersionUID = 1L;

        @Override
        void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException
        {
            setStatus(CONSTRAINT_EVALUATION_STATUS.ACCEPTED);
        }

        @Override
        void evaluatePersistentCopy(ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord primitiveRecord, JODBOperationContext context) throws IOException
        {
            setStatus(CONSTRAINT_EVALUATION_STATUS.ACCEPTED);
        }

        public Constraint contains() {
            // TODO Auto-generated method stub
            throw new RuntimeException("Not Implemented");
            //return null;
        }

        public Constraint equal() {
            // TODO Auto-generated method stub
            throw new RuntimeException("Not Implemented");
            //return null;
        }

        public Object getObject() {
            // TODO Auto-generated method stub
            throw new RuntimeException("Not Implemented");
            //return null;
        }

        public Constraint greater() {
            // TODO Auto-generated method stub
            throw new RuntimeException("Not Implemented");
            //return null;
        }

        public Constraint identity() {
            // TODO Auto-generated method stub
            throw new RuntimeException("Not Implemented");
            //return null;
        }

        public Constraint like() {
            // TODO Auto-generated method stub
            throw new RuntimeException("Not Implemented");
            //return null;
        }

        public Constraint not() {
            // TODO Auto-generated method stub
            throw new RuntimeException("Not Implemented");
            //return null;
        }

        public Constraint smaller() {
            // TODO Auto-generated method stub
            throw new RuntimeException("Not Implemented");
            //return null;
        }
       
    }
   
   
    private abstract static class ConstraintBase implements Constraint, Serializable{
       
        private transient ThreadLocal<CONSTRAINT_EVALUATION_STATUS> _status;
       
        private Vector<ConstraintBase> _links = new Vector<ConstraintBase>(2);

        public ConstraintBase() {
            initStatus();
        }
       
        void updateSession(JODBSession session){
           
        }
       
        private void initStatus(){
            _status = new ThreadLocal<CONSTRAINT_EVALUATION_STATUS>() {
                @Override
                protected CONSTRAINT_EVALUATION_STATUS initialValue()
                {
                    return CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
                }
            };
        }
       
        public void resetStatus(){
            _status.set(CONSTRAINT_EVALUATION_STATUS.UNKNOWN);
        }
       
        public Object readResolve() throws ObjectStreamException{
            initStatus();
            return this;
        }
       
        public void setStatus(CONSTRAINT_EVALUATION_STATUS newStatus){
            _status.set(newStatus);
        }
       
       
        public Constraint and(Constraint with) {
            ConstraintBase withImpl = (ConstraintBase) with;
            ConstraintLink link = new ConstraintLink(false,this, withImpl);
            _links.add(link);
            withImpl._links.add(link);
            return link;
        }
       
        public CONSTRAINT_EVALUATION_STATUS getStatus() {
            return _status.get();
        }
       
        public CONSTRAINT_EVALUATION_STATUS getCumulativeStatus() {
            synchronized (_links) {
                if(_links.size()==0){
                    return _status.get();
                }
                int acceptedCount = 0;
                for (int i = 0; i < _links.size(); i++) {
                    switch (_links.elementAt(i).getCumulativeStatus()) {
                    case ACCEPTED:
                        acceptedCount++;
                        break;
                    case REJECTED:
                        return CONSTRAINT_EVALUATION_STATUS.REJECTED;
                    }
                }
                if(acceptedCount == _links.size()){
                    return CONSTRAINT_EVALUATION_STATUS.ACCEPTED;
                }else{
                    return CONSTRAINT_EVALUATION_STATUS.UNKNOWN;
                }
            }
        }
       
        abstract void evaluatePersistentCopy( ClassDescriptor classDescriptor, ObjectDataContainer dataContainer, FieldRecord primitiveRecord, JODBOperationContext context) throws IOException;
       
        abstract void evaluateActiveObject(Object activeObject, Field field, JODBOperationContext context) throws IOException;
       

        public Constraint or(Constraint with) {
            ConstraintBase withImpl = (ConstraintBase) with;
            ConstraintLink link = new ConstraintLink(true,this, withImpl);
            _links.add(link);
            withImpl._links.add(link);
            return link;
        }
       
    }
}
TOP

Related Classes of com.mobixess.jodb.core.query.QueryNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.