private SelectResults evaluateAndJunction(ExecutionContext context)
      throws FunctionDomainException, TypeMismatchException, NameResolutionException,
      QueryInvocationTargetException {
    // Asif: We will evaluate the iter operand while getting the result of
    // composite condition iff there exists only one Filterable Composite
    // Condition & no GroupJunction
    CompiledValue iterOp = null;
    SelectResults intermediateResults = null;
    // TODO: Check if null can come for the iter operand List
    if (iterOperands != null && !iterOperands.isEmpty()) {
      int len = iterOperands.size();
      if (len == 1) {
        iterOp = (CompiledValue) iterOperands.get(0);
      } else {
        CompiledValue[] newOperands = new CompiledValue[len];
        newOperands = (CompiledValue[]) iterOperands.toArray(newOperands);
        iterOp = new CompiledJunction(newOperands, operator);
      }
    }
    SortedSet intersectionSet = new TreeSet(new SelectResultsComparator());
    // TODO:Asif: Clean this logic. If the iter operand is not null when should
    // we evaluate it.? Ideally if we were to stick to our logic of delaying
    // evaluation of condition , then we shoudl ideally first do intersection of
    // results obtained using indexes on conditions & then apply iter operand on
    // it. But some how it appears that the final iteration will be more
    // expensive then evaluation. So we use for time being following idea. If
    // the iter condition is not null & there exists atleast one Group Junction
    // ( then we are sure it will need expansion to CompositeGroupJunction
    // level, so the iter operand can be evaluated at that point, else we will
    // evaluate it with the first available filterable cc

    // Asif : Obtain results of Filter evaluatable composite conditions
    // Support.Assert( iterOp == null || ( iterOp !=null &&
    // this.filterableCC.size() == 1 && this.groupJunctions == null), "The Iter
    // operand can be not null only if there exists single filterable CC & no
    // group junction");
    boolean delayIterOpEval = (groupJunctions != null && groupJunctions.size() != 0);
    Iterator itr = filterableCC.iterator();
    int filterableCCSize = filterableCC.size();
    if (filterableCCSize > 1) {
      for (int i = 0; i < (filterableCCSize - 1); i++) {
        CompiledValue cc = (CompiledValue) itr.next();
        intermediateResults = ((Filter) cc).filterEvaluate(context, intermediateResults, false,
            null/* iterOpn = null */, null/* send independent itrs null */, false, true, false);
        if (intermediateResults.isEmpty()) {
          StructType structType = QueryUtils.createStructTypeForRuntimeIterators(
              completeExpansion ? context.getCurrentIterators()
                  : QueryUtils.getDependentItrChainForIndpndntItrs(indpndnts, context));
          return QueryUtils.createStructCollection(context, structType);
        }
      }
    }
    CompiledValue cc = (CompiledValue) itr.next();
    intermediateResults = ((Filter) cc).filterEvaluate(context, intermediateResults,
        completeExpansion, delayIterOpEval ? null : iterOp,
        indpndnts /*
                   * Since this is the last condition pass the indpndt. grp of itrs so that
                   * result structset with correct placement of itrs can be formed
                   */, false, true, false);
    intersectionSet.add(intermediateResults);
    intermediateResults = null;
    if (iterOp != null && !delayIterOpEval) {
      iterOp = null;
    }
    Support.Assert(iterOp == null || (groupJunctions != null),
        "The Iter operand can be not null only if there exists atleast one group junction");
    // TODO:Asif Put this function in some Util class so that both
    // AllGroupJunction & CompositeGroupJunction
    // can use it. Identify a cleaner approach to it other than null check
    if (groupJunctions != null) {
      int len = groupJunctions.size();
      if (len > 1) {
        // Asif : Create an array of SelectResults for each of the GroupJunction
        // For each Group Junction there will be a corresponding array of
        // RuntimeIterators
        // which will map to the fields of the ResultSet obtained from
        // Group Junction
        SelectResults[] results = new SelectResults[len];
        // Asif : the final list will be some of all the iterators depending on
        // each of indpendent group if complete expansion is not needed
        List finalList = null;
        if (completeExpansion) {
          finalList = context.getCurrentIterators();
        } else {
          finalList = QueryUtils.getDependentItrChainForIndpndntItrs(indpndnts, context);
        }
        List expansionList = new LinkedList(finalList);
        RuntimeIterator[][] itrsForResultFields = new RuntimeIterator[len][];
        AbstractGroupOrRangeJunction gj = null;
        Iterator junctionItr = groupJunctions.iterator();
        List grpItrs = null;
        int j = 0;
        RuntimeIterator tempItr = null;
        while (junctionItr.hasNext()) {
          gj = (AbstractGroupOrRangeJunction) junctionItr.next();
          SelectResults filterResults = ((Filter) gj).filterEvaluate(context, null);
          Support.Assert(filterResults != null, "FilterResults cannot be null here");
          if (filterResults.isEmpty()) {
            // TODO Asif : Compact the code of creation of empty set.
            // Asif: Create an empty resultset of the required type & return
            // it. e cannot use the existing Resultset as it may not be expanded
            // to the required level.
            SelectResults empty = null;
            if (finalList.size() == 1) {
              ObjectType type = ((RuntimeIterator) finalList.iterator().next()).getElementType();
              if (type instanceof StructType) {
                empty = QueryUtils.createStructCollection(context, (StructTypeImpl) type);
              } else {
                empty = QueryUtils.createResultCollection(context, type);
              }
            } else {
              StructType strucType = QueryUtils.createStructTypeForRuntimeIterators(finalList);
              empty = QueryUtils.createStructCollection(context, strucType);
            }
            return empty;
          } else {
            results[j] = filterResults;
            grpItrs = context.getCurrScopeDpndntItrsBasedOnSingleIndpndntItr(
                gj.getIndependentIteratorForGroup()[0]);
            itrsForResultFields[j] = new RuntimeIterator[grpItrs.size()];
            Iterator grpItr = grpItrs.iterator();
            int k = 0;
            while (grpItr.hasNext()) {
              tempItr = (RuntimeIterator) grpItr.next();
              itrsForResultFields[j][k++] = tempItr;
              expansionList.remove(tempItr);
            }
            ++j;
          }
        }
        // Do the cartesian of the different group junction results.
        // TODO:Asif Remove the time
        QueryObserver observer = QueryObserverHolder.getInstance();
        observer.beforeCartesianOfGroupJunctionsInCompositeGroupJunctionOfType_AND(results);
        SelectResults grpCartRs = QueryUtils.cartesian(results, itrsForResultFields, expansionList,
            finalList, context, iterOp);
        observer.afterCartesianOfGroupJunctionsInCompositeGroupJunctionOfType_AND();
        Support.Assert(grpCartRs != null, "ResultsSet obtained was NULL in CompositeGroupJunction");
        intersectionSet.add(grpCartRs);
      } else {
        // TODO:Asif : Examine this logic as expansion of a GroupJunction to a a
        // CompositeGroupJunction level may not be a good idea, as each filter
        // evaluatable condition in a GroupJunction will have to be
        // unnecessarily expanded to the Composite GroupJunction level . This
        // will be a heavy operation & also the size of the sets to be
        // intersected will also be quite large. Ideally we should expand the
        // GroupJunction to CompositeGroupJunction level only if there exists a
        // single filter evaluatable condition in a GroupJunction. Asif : If
        // there exists only one GroupJunction in a CompsoiteGroupJunction ,
        // then we can afford to expand the result of GroupJunction to the level
        // of CompositeGroupJunction directly within the GroupJunction Thus
        // create a new GroupJunction with independent group of iterators same
        // as that of CompositeGroupJunction if complete expansion is false. If
        // complete expansion is true then create a new GroupJunction only if
        // there is residual iter operand. Thus this is the only special case (&
        // iff completeExpansion boolean false) where in a GroupJunction will
        // contain more than one independent iterators TODO:ASIF: CHECK IT
        // OUT..................

        AbstractGroupOrRangeJunction newGJ =
            (AbstractGroupOrRangeJunction) groupJunctions.get(0);
        if (!completeExpansion) {
          newGJ = newGJ.recreateFromOld(completeExpansion, indpndnts, iterOp);
        } else if (iterOp != null) {
          // Asif :Complete expansion is true. In this case we should not pass
          // the Group of iterators belonging to the CompositeGroupJunction but
          // stick to independent iterator for the group. Also we are creating a
          // new GroupJunction below only bcoz of extra iter operand. For
          // toggling the complete xpansion flag of Grp Junction to on , that
          // task is alreday done. in setCompleteExpansionOn of CGJ

          newGJ = newGJ.recreateFromOld(completeExpansion,
              newGJ.getIndependentIteratorForGroup(), iterOp);
        }
        SelectResults rs = newGJ.filterEvaluate(context, null);
        if (rs.isEmpty()) {
          return rs;
        } else {
          intersectionSet.add(rs);
        }
      }
    }
    for (final Object o : intersectionSet) {
      SelectResults sr = (SelectResults) o;
      intermediateResults = (intermediateResults == null) ? sr
          : QueryUtils.intersection(intermediateResults, sr, context);
    }
    return intermediateResults;
  }
@param temp CompositeGroupJunction which gets merged in this CompositeGroupJunction. This
       fusion occurs during creation of junction if the order in which the conditions of where
       clause arrival are such that condition1 tying region1 & region2 , condition 2 tying
       region 3 & region 4 and condition 3 tying region 3 and region 4. In such case , finally
       it should result in a single CompositeGroupJunction containing region1, region2 , region
       3 and region4 conditions and theire correspodning GroupJunctions if any.
geode-core/src/main/java/org/apache/geode/cache/query/internal/CompositeGroupJunction.java