private Filter createJunction(List compositeIterOperands, Map compositeFilterOpsMap,
      Map iterToOperands, ExecutionContext context, int indexCount, List evalOperands,
      boolean indexExistsOnNonJoinOp) throws FunctionDomainException, TypeMismatchException,
      NameResolutionException, QueryInvocationTargetException {
    Support.Assert(!(iterToOperands.isEmpty() && compositeFilterOpsMap.isEmpty()),
        " There should not have been any need to create a Junction");
    CompiledValue junction = null;
    int size;
    /*---------- Create only a  GroupJunction */
    if (iterToOperands.size() == 1 && (compositeFilterOpsMap.isEmpty()
        || (indexExistsOnNonJoinOp && IndexManager.JOIN_OPTIMIZATION))) {
      if ((indexExistsOnNonJoinOp && IndexManager.JOIN_OPTIMIZATION)) {
        // For the optimization we will want to add the compositeFilterOpsMap 848
        // without the optimization we only fall into here if it's empty anyways, but have not
        // tested the removal of this if clause
        evalOperands.addAll(compositeFilterOpsMap.keySet());
      }
      // Asif :Create only a GroupJunction. The composite conditions can be
      // evaluated as iter operands inside GroupJunction.
      Map.Entry entry = (Map.Entry) iterToOperands.entrySet().iterator().next();
      List operandsList = (List) entry.getValue();
      // Asif: If there exists no other filter operand, transfer all the
      // remaining iter operands to the Group Junction. Else transfer all the
      // remaining operands to eval operands of CompiledJunctio. This means that
      // we are following the logic that as far as possible minimize the
      // result-set used for iter evaluation of conditions without index.
      // This way we also save on extra iterations for eval conditions if they
      // existed both in GroupJunction as well as CompiledJunction. The only
      // exception in this logic is the iter evaluable conditions belonging to a
      // GroupJunction.
      // If a condition is dependent on a Single Group & is not filter evaluable
      // we do not push it out to iter operands of AllGroupJunction or Compiled
      // Junction , but make it part of GroupJunction itself. This helps bcoz we
      // are sure that the condition will be completely evaluable by the
      // iterators of that group itself.
      if (indexCount == 0) {
        operandsList.addAll(evalOperands);
        evalOperands.clear();
        if (!compositeIterOperands.isEmpty()) {
          operandsList.addAll(compositeIterOperands);
        }
      } else {
        if (!compositeIterOperands.isEmpty()) {
          evalOperands.addAll(compositeIterOperands);
        }
        Iterator itr = operandsList.iterator();
        while (itr.hasNext()) {
          CompiledValue cv = (CompiledValue) itr.next();
          // Asif : Those conditions not filter evaluable are transferred to
          // eval operand of CompiledJunction.
          if (!cv.getPlanInfo(context).evalAsFilter) {
            itr.remove();
            evalOperands.add(cv);
          }
        }
      }
      size = operandsList.size();
      Map sameIndexOperands = new HashMap(size);
      CompiledValue[] cv = new CompiledValue[size];
      // Enable only for AND junction
      boolean needsCompacting =
          sortSameIndexOperandsForGroupJunction(cv, operandsList, sameIndexOperands, context);
      junction = createGroupJunctionOrRangeJunction(needsCompacting,
          new RuntimeIterator[] {(RuntimeIterator) entry.getKey()},
          true /* need a Complete expansion */, cv, sameIndexOperands);
    }
    /*
     * Asif : An AllGroupJunction or a CompositeGroupJunction can get created. An AllGroupJunction
     * will get created , if there exists a need to create more than one CompositeGroupJunction
     * AND/OR more than one GroupJunctions ( not part of CompositeGroupJunction) If suppose the
     * where clause contained two sets of conditions each dependent exclusively on a separate
     * independent group ( implying two independent groups) then we should create an
     * AllGroupJunction iff the two Groups are both filter evaluable. If an AllGroupJunction
     * contains only one filter evaluable Group & no CompositeGroupJunction then we should just
     * create a singleGroupJunction with complete expansion as true
     */
    else {
      // Asif : First create the required amount of CompositeGroupJunctions
      // A map which keeps track of no. of independent iterators pointing to the
      // same CompositeGroupJunction. The integer count will keep track of
      // number of different CompositeGroupJunctions which got created.
      Map tempMap = new HashMap();
      Set entries = compositeFilterOpsMap.entrySet();
      Set cgjs = new HashSet(compositeFilterOpsMap.size());
      for (final Object o : entries) {
        Map.Entry entry = (Map.Entry) o;
        CompiledValue op = (CompiledValue) entry.getKey();
        Set indpndtItrSet = (Set) entry.getValue();
        Iterator itr = indpndtItrSet.iterator();
        CompositeGroupJunction cgj = null;
        RuntimeIterator[] absentItrs = new RuntimeIterator[2];
        int k = 0;
        while (itr.hasNext()) {
          RuntimeIterator ritr = (RuntimeIterator) itr.next();
          CompositeGroupJunction temp = (CompositeGroupJunction) tempMap.get(ritr);
          if (temp == null) {
            absentItrs[k++] = ritr;
          }
          if (cgj == null && temp != null) {
            cgj = temp;
            cgj.addFilterableCompositeCondition(op);
          } else if (cgj != null && temp != null && cgj != temp) {
            // Asif A peculiar case wherein we have some thing like four regions
            // with relation ship conditions like r1 = r2 and r3 = r4 and r4 =
            // r1. In such situations we should just have a single
            // CompositeJunction containing r1 r2 r3 and r4 We will merge temp
            // into CompositeGroupJunction & change all the values in tempMap
            // which contained temp object to CompositeGroupJunction.
            // Also we will remove the entry of temp from CompositeGroupJunctions.
            cgj.mergeFilterableCCsAndIndependentItrs(temp);
            cgjs.remove(temp);
            Iterator entriesItr = tempMap.entrySet().iterator();
            Map.Entry tempEntry = null;
            while (entriesItr.hasNext()) {
              tempEntry = (Map.Entry) entriesItr.next();
              if (tempEntry.getValue() == temp) {
                tempEntry.setValue(cgj);
              }
            }
          }
        }
        if (cgj == null) {
          // Asif Create a new CompositeGroupJunction
          cgj = new CompositeGroupJunction(_operator, op /* CompositeFilterOperand */);
          cgjs.add(cgj);
        }
        for (int i = 0; i < k; ++i) {
          tempMap.put(absentItrs[i], cgj);
          cgj.addIndependentIterators(absentItrs[i]);
        }
      }
      // Asif :If no of cgj is zero definitely there will be an AllGroupJunction
      // If no. of cgj is more than 1 , then also there will be an AllGroupJunction.
      // But if no. of cgj is excactly one & all the GroupJunctions can be
      // accomodated within the CGJ , then we will have CompsiteGroupJunction.
      // Also , those composite conditions which are not filter evaluable will
      // be added to CompositeGroupJunction as iter operands only if we don't
      // have any additional filter & CompositeGroupJunction is the only
      // junction which will get created. If there exists any other filter then
      // it will be part of CompiledJunction's iter operand. Basically we will
      // not distinguish between various CompositeConditions which are not
      // filter evaluable & will not try to place it in various
      // ComspoiteGroupJunctions to which they belong.
      List gjs = new ArrayList(iterToOperands.size());
      Iterator itr = iterToOperands.entrySet().iterator();
      Map.Entry entry;
      while (itr.hasNext()) {
        entry = (Map.Entry) itr.next();
        List operandsList = (List) entry.getValue();
        CompiledValue[] cv = new CompiledValue[size = operandsList.size()];
        int j = 0;
        // Asif:An individual GroupJunction is Filter evaluable if at least one
        // operand is filter evaluable.
        boolean evalAsFilter = false;
        boolean needsCompacting = false;
        CompiledValue tempOp = null;
        Map sameIndexOperands = new HashMap(size);

        for (; j < size; ++j) {
          tempOp = (CompiledValue) operandsList.get(j);
          boolean isFilterevaluable = tempOp.getPlanInfo(context).evalAsFilter;
          evalAsFilter = evalAsFilter || isFilterevaluable;
          IndexInfo[] indx = null;
          Object listOrPosition = null;
          if (isFilterevaluable) {
            indx = ((Indexable) tempOp).getIndexInfo(context);
            Assert.assertTrue(indx.length == 1,
                "There should have been just one index for the condition");
            listOrPosition = sameIndexOperands.get(indx[0]._index);
          }
          if (listOrPosition != null) {
            if (listOrPosition instanceof Integer) {
              int position = (Integer) listOrPosition;
              List operands = new ArrayList(size);
              operands.add(cv[position]);
              operands.add(tempOp);
              cv[position] = null;
              sameIndexOperands.put(indx[0]._index, operands);
              needsCompacting = true;
            } else {
              List operands = (List) listOrPosition;
              operands.add(tempOp);
            }
          } else {
            cv[j] = tempOp;
            if (isFilterevaluable && _operator == OQLLexerTokenTypes.LITERAL_and) {
              sameIndexOperands.put(indx[0]._index, j);
            }
          }
        }
        if (!evalAsFilter) {
          // Asif : If there exists at least one Filter then those GroupJunction
          // which are not Filter evaluable should become part of eval operands
          // of CompiledJunction else add the Group operands which is not filter
          // evaluable to the Composite iterator oprands
          List toAddTo = null;
          if (indexCount > 0) {
            toAddTo = evalOperands;
          } else {
            toAddTo = compositeIterOperands;
          }
          for (int i = 0; i < size; ++i) {
            toAddTo.add(cv[i]);
          }
        } else {
          RuntimeIterator grpIndpndtItr = (RuntimeIterator) entry.getKey();
          AbstractGroupOrRangeJunction gj = createGroupJunctionOrRangeJunction(needsCompacting,
              new RuntimeIterator[] {(RuntimeIterator) entry.getKey()},
              false/* Expand only to Group Level */, cv, sameIndexOperands);
          CompositeGroupJunction cgj = null;
          if ((cgj = (CompositeGroupJunction) tempMap.get(grpIndpndtItr)) != null) {
            cgj.addGroupOrRangeJunction(gj);
          } else {
            gjs.add(gj);
          }
        }
      }
      if (indexCount == 0) {
        // Asif : all the eval operands of CompiledJunction should be part of
        // AllGroupJunction
        compositeIterOperands.addAll(evalOperands);
        evalOperands.clear();
      } else {
        // Asif : Add the composite operands to the eval operands so that they
        // are evaluated as part of CompiledJunction.
        if (!compositeIterOperands.isEmpty()) {
          evalOperands.addAll(compositeIterOperands);
        }
      }
      // Asif : An AllGroupJunction will be created iff either the List
      // containing GroupJunctions is not empty ot there exists multiple
      // CompositeGroupJunctions Else a CompositeGroupJunction will be created
      // Convert the List of Indpendent Runtime Iterators of
      // CompositeGroupJunction into Array of Indpendent RuntimeIterators
      for (final Object cgj : cgjs) {
        ((CompositeGroupJunction) cgj).setArrayOfIndependentItrs();
      }
      int cgjSize = cgjs.size();
      if (gjs.isEmpty() && cgjSize == 1) {
        CompositeGroupJunction compGrpJnc = (CompositeGroupJunction) cgjs.iterator().next();
        compGrpJnc.addIterOperands(compositeIterOperands);
        compGrpJnc.setCompleteExpansionOn();
        junction = compGrpJnc;
      } else if (gjs.size() == 1 && cgjSize == 0) {
        // Asif: There exists only a single Filterable GroupJunction & no
        // CompositeGroupJunction so we should just create a GroupJunction
        // instead of an AllGroupJunction . ( In this way the remaining iter
        // operands will get evaluated during the filter evaluation of
        // GroupJunction) For such GroupJunction complete expansion needs to be
        // true & the list of composite iter operands ( which at this point
        // contains the iter operands, should be added to the operands of
        // GroupJunction where they will get orgainzed as iter operands during
        // the call of organizeOperands in GroupJunction
        AbstractGroupOrRangeJunction gjTemp = (AbstractGroupOrRangeJunction) gjs.get(0);
        compositeIterOperands.addAll(gjTemp.getOperands());
        CompiledValue[] newOps = new CompiledValue[compositeIterOperands.size()];
        compositeIterOperands.toArray(newOps);
        // Asif : If gjTemp is a RangeJunction, we will get an instance of
        // RangeJunction else we will get an instance of GroupJunction.
        junction =
            gjTemp.createNewOfSameType(_operator, gjTemp.getIndependentIteratorForGroup(),
                true/* The expansion needs to be complete */, newOps);

      } else {
        gjs.addAll(cgjs);
        junction = new AllGroupJunction(gjs, _operator, compositeIterOperands);
      }
    }
    return (Filter) junction;
  }
Creates a GroupJunction or a RangeJunction based on the operands passed. The operands are
either Filter Operands belonging to single independent RuntimeIterator or are iter evaluable on
the RuntimeIterator[] passed as parameter. If all the filter evaluable operands use a single
Index , than a RangeJunction is created with iter operand as part of RangeJunction. If there
exists operands using multiple indexes, then a GroupJunction is created. In that case , the
operands using the same index are grouped in a RangeJunction & that Range Junction becomes part
of the GroupJunction. A GroupJunction may contain one or more RangeJunction

@param needsCompacting boolean indicating if there is a possibility of RangeJunction or not. If
       needsCompacting is false , then a GroupJunction will be formed, without any
       RangeJunction
@param grpIndpndntItr Array of RuntimeIterator which represents the independent iterator for
       the Group. for all cases , except a CompositeGroupJunction containing a single
       GroupJunction , will have a single RuntimeIterator in this array.
@param completeExpnsn boolean indicating whether the Group or Range Junction needs to be
       expanded to the query from clause level or the group level
@param cv Array of CompiledValue containing operands belonging to a group
@param sameIndexOperands Map object containing Index as the key & as a value an Integer object
       or a List. If it contains an Integer as value against Index, it implies that there is
       only one operand which uses that type of index & hence cannot form a RangeJunction. If
       it contains a List then the Lis contains the operands which use same index & thus can
       form a RangeJunction
@return Object of GroupJunction or RangeJunction as the case may be
geode-core/src/main/java/org/apache/geode/cache/query/internal/CompiledJunction.java