All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gemstone.gemfire.cache.query.internal.RuntimeIterator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License. You
 * may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License. See accompanying
 * LICENSE file.
 */
package com.gemstone.gemfire.cache.query.internal;

import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import java.util.*;
import java.lang.reflect.Method;
import com.gemstone.gemfire.cache.query.*;
import com.gemstone.gemfire.cache.query.internal.index.IndexCreationHelper;
import com.gemstone.gemfire.cache.query.internal.types.TypeUtils;
import com.gemstone.gemfire.cache.query.types.*;

/**
 * Value representing a current iteration element. This is the representation
 * used during evaluation.
 * 
 * A RuntimeIterator can be in one of two states. If it is independent of the
 * current context scope then its collection is evaluated lazily, in which case
 * collection is initialized and knows its elementType. The elementType field is
 * the same value as in the collection. Otherwise, collection is UNINITIALIZED
 * and the elementType is set in any case.
 * 
 * A RuntimeIterator can also be named or anonymous (name is null).
 * 
 * @author ericz
 */
public class RuntimeIterator extends AbstractCompiledValue  {

  // token to differentiate null from uninitialized
  private static final SelectResults UNINITIALIZED = new ResultsBag(0, null);
  private Object current = UNINITIALIZED;
  private String name;
  private SelectResults collection = UNINITIALIZED;
  private CompiledIteratorDef cmpIteratorDefn;
  private ObjectType elementType; // may be more specific than that in
  // cmpIteratorDefn
  // for canonicalization
  private String internalId = null;
  private String definition = null;
  private String index_internal_id = null;
  private int scopeID = -1;

  public int getType() {
    return ITERATOR_DEF;
  }

  public ObjectType getElementType() {
    return this.elementType;
  }

  RuntimeIterator(CompiledIteratorDef cmpIteratorDefn, ObjectType elementType) {
    if (elementType == null || cmpIteratorDefn == null) { throw new IllegalArgumentException(LocalizedStrings.RuntimeIterator_ELEMENTTYPE_ANDOR_CMPITERATORDEFN_SHOULD_NOT_BE_NULL.toLocalizedString()); }
    this.name = cmpIteratorDefn.getName();
    this.elementType = elementType;
    this.cmpIteratorDefn = cmpIteratorDefn;
  }

  //  public RuntimeIterator(String name, SelectResults collection) {
  //    if (collection == null)
  //      throw new IllegalArgumentException("base collection must not be null");
  //    
  //    this.name = name; // may be null
  //    this.collection = collection;
  //    this.cmpIteratorDefn = null;
  //    this.elementType = collection.getCollectionType().getElementType();
  //  }
  //  /** Return true if this is an iterator that is dependent on other
  // iterator(s)
  //   * in this scope (a cached result from isDependentOn(context))
  //   */
  //  public boolean isDependent() {
  //    return this.isDependent;
  //  }
  CompiledIteratorDef getCmpIteratorDefn() {
    return this.cmpIteratorDefn;
  }

  public String getName() {
    return this.name;
  }

  /**
   * (Re)evaluate in the context of the current iterations through the
   * cross-product. If this iterator is not dependent on the current iteration,
   * then just return the previously evaluated collection. Otherwise,
   * re-evaluate. Returns null if the collection itself is null or UNDEFINED
   */
  public SelectResults evaluateCollection(ExecutionContext context)
      throws FunctionDomainException, TypeMismatchException,
      NameResolutionException, QueryInvocationTargetException {
    if (this.collection != UNINITIALIZED     
    		&& !this.cmpIteratorDefn.isDependentOnAnyIteratorOfScopeLessThanItsOwn(context) 
    		&& this.scopeID != IndexCreationHelper.INDEX_QUERY_SCOPE_ID) { return this.collection; }
    // limit the scope for evaluation to this RuntimeIterator:
    // we don't want to use this iterator or subsequent ones in the from clause
    // to evaluate this collection.
    this.collection = this.cmpIteratorDefn.evaluateCollection(context, this);
    if (this.collection == null) { return null; }
    // if we already have a more specific elementType, set it in the collection
    if (!this.elementType.equals(TypeUtils.OBJECT_TYPE)) {
      this.collection.setElementType(elementType);
    }
    else {
      // Asif : The elementType in the Collection obtained is more
      //specific . So use that type.
      this.elementType = collection.getCollectionType().getElementType();
    }
    return this.collection;
  }

  @Override
  public Set computeDependencies(ExecutionContext context) {
    // called as the receiver of Path or Operation
    return Collections.singleton(this);
  }

  @Override
  public boolean isDependentOnIterator(RuntimeIterator itr,
      ExecutionContext context) {
    if (itr == this) return true; // never true(?)
    return this.cmpIteratorDefn.isDependentOnIterator(itr, context);
  }

  @Override
  public boolean isDependentOnCurrentScope(ExecutionContext context) {
    return this.cmpIteratorDefn.isDependentOnCurrentScope(context);
  }

  public void setCurrent(Object current) {
    this.current = current;
  }

  public Object evaluate(ExecutionContext context) {
    if(current == UNINITIALIZED) {
      System.out.println("asif");
    }
    Support.Assert(current != UNINITIALIZED,
        "error to evaluate RuntimeIterator without setting current first");
    return this.current;
  }

  boolean containsProperty(String name, int numArgs, boolean mustBeMethod)
      throws AmbiguousNameException {
    // first handle structs
    if ((this.elementType instanceof StructType) && !mustBeMethod) {
      //check field names
      String fieldName[] = ((StructType) this.elementType).getFieldNames();
      for (int i = 0; i < fieldName.length; i++) {
        if (name.equals(fieldName[i])) { return true; }
      }
    }
    Class clazz = this.elementType.resolveClass();
    if (numArgs > 0 || mustBeMethod) {
      // if numArgs==0, then just look up method directly
      // instead of sifting through all methods
      if (numArgs == 0) {
        try {
          clazz.getMethod(name, (Class[])null);
          return true;
        }
        catch (NoSuchMethodException e) {
          return false;
        }
      }
      // enumerate methods and match with name
      // here, only check for a method with the same number of arguments.
      // we'll check for ambiguous method invocation when the method is
      // actually fully resolved and invoked
      Method[] methods = clazz.getMethods();
      for (int i = 0; i < methods.length; i++) {
        Method m = methods[i];
        if (m.getName().equals(name) && m.getParameterTypes().length == numArgs)
            return true;
      }
      return false;
    }
    // if there are zero arguments and it's an attribute, then defer to
    // AttributeDescriptor
    // to see if there's a match
    return new AttributeDescriptor(name).validateReadType(clazz);
  }

  //  private SelectResults prepareIteratorDef(Object obj)
  //  throws TypeMismatchException {
  //    if (obj == null) {
  //      return null;
  //    }
  //
  //    if (obj == QueryService.UNDEFINED) {
  //      return null;
  //    }
  //
  //    if (obj instanceof SelectResults) {
  //      // probably came from nested query or is a QRegion already from region
  // path
  //      return (SelectResults)obj;
  //    }
  //
  //    if (obj instanceof Region) {
  //      return new QRegion((Region)obj); // this can happen if region passed in as
  // parameter
  //    }
  //
  //    // if this is a domain collection, it should be unmodifiable
  //    // if obj is a Collection but not a SelectResults, it must be from the
  //    // domain, otherwise it would be a SelectResults.
  //    if (obj instanceof Collection) {
  //      // do not lose ordering and duplicate information,
  //      ResultsCollectionWrapper res =
  //              new ResultsCollectionWrapper(this.elementType, (Collection)obj);
  //      res.setModifiable(false);
  //      return res;
  //    }
  //
  //    // Object[] is wrapped and considered a domain object so unmodifiable
  //    if (obj instanceof Object[]) {
  //      // the element type is specified in the array itself, unless we have
  //      // something more specific
  //      if (this.elementType.equals(TypeUtils.OBJECT_TYPE)) { // if we don't have
  // constraint info
  //        this.elementType =
  // TypeUtils.getObjectType(obj.getClass().getComponentType());
  //      }
  //
  //      // do not lose ordering and duplicate information,
  //      ResultsCollectionWrapper res =
  //              new ResultsCollectionWrapper(this.elementType,
  // Arrays.asList((Object[])obj));
  //      res.setModifiable(false);
  //      return res;
  //    }
  //
  //    if (obj instanceof Map) {
  //      if (this.elementType.equals(TypeUtils.OBJECT_TYPE)) { // if we don't have
  // more specific type info, use Map.Entry
  //        elementType = TypeUtils.getObjectType(Map.Entry.class);
  //      }
  //      ResultsCollectionWrapper res =
  //              new ResultsCollectionWrapper(elementType, ((Map)obj).entrySet());
  //      res.setModifiable(false);
  //      return res;
  //    } else {
  //      throw new TypeMismatchException(
  //              "The expression in the FROM clause of a SELECT statement was type '"
  //              + obj.getClass().getName()
  //              + "', which cannot be interpreted as a collection");
  //    }
  //  }
  @Override
  public String toString() {
    StringBuffer sb = new StringBuffer();
    sb.append(this.getClass().getName());
    sb.append(" (name=" + this.name);
    //    if(isDependent)
    sb.append(" collection expr=" + cmpIteratorDefn);
    //    else {
    //      sb.append("; collection=" +this.collection + ")");
    //      sb.append("; collectionType=" +this.collection.getCollectionType() +
    // ")");
    //      sb.append("; elementType="
    // +this.collection.getCollectionType().getElementType() + ")");
    //    }
    return sb.toString();
  }

  // Canonicalization
  public void setInternalId(String id) {
    // it's okay for this to be set more than once; a RuntimeIterator
    // can be bound to a scope to compute dependencies, then
    // re-bound to a different scope later at eval time.
    //    Support.Assert((internalId == null), "Internal ID is already set");
    Support.Assert((id != null), "Internal ID can not be null");
    internalId = id;
  }

  public String getInternalId() {
    //Support.Assert((internalId != null), "Internal ID is not yet set");
    return internalId;
  }

  public void setDefinition(String def) {
    Support.Assert((definition == null), "Definition is already set");
    Support.Assert((def != null), "Definition can not be null");
    definition = def;
  }

  public void setIndexInternalID(String index_id) {
    this.index_internal_id = index_id;
  }

  public String getIndexInternalID() {
    return this.index_internal_id;
  }

  public String getDefinition() {
    Support.Assert((definition != null), "Definition is not yet set");
    return definition;
  }

  @Override
  public void generateCanonicalizedExpression(StringBuffer clauseBuffer,
      ExecutionContext context) throws AmbiguousNameException,
      TypeMismatchException {
    //Asif: prepend the internal iterator variable name for this
    // RunTimeIterator
    //
    int currScopeID = context.currentScope().getScopeID();
    if (currScopeID == this.scopeID) {
      // Support.Assert(this.index_internal_id != null, "Index_Internal_ID
      // should have been set at this point");
      clauseBuffer.insert(0, this.index_internal_id == null ? this.internalId
          : this.index_internal_id);
    }
    else {
      clauseBuffer.insert(0, internalId).insert(0, '_').insert(0, this.scopeID)
          .insert(0, "scope");
    }
  }

  void setScopeID(int scopeID) {
    this.scopeID = scopeID;
  }

  int getScopeID() {
    return this.scopeID;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy