/** Used for forced update of a bean. */
  public PersistRequestBean(
      SpiEbeanServer server,
      T bean,
      Object parentBean,
      BeanManager<T> mgr,
      SpiTransaction t,
      PersistExecute persistExecute,
      Set<String> updateProps,
      ConcurrencyMode concurrencyMode) {

    super(server, t, persistExecute);
    this.beanManager = mgr;
    this.beanDescriptor = mgr.getBeanDescriptor();
    this.beanPersistListener = beanDescriptor.getPersistListener();
    this.bean = bean;
    this.parentBean = parentBean;

    this.controller = beanDescriptor.getPersistController();
    this.concurrencyMode = beanDescriptor.getConcurrencyMode();

    this.concurrencyMode = concurrencyMode;
    this.loadedProps = updateProps;
    this.changedProps = updateProps;

    this.vanilla = true;
    this.isDirty = true;
    this.oldValues = bean;
    if (bean instanceof EntityBean) {
      this.intercept = ((EntityBean) bean)._ebean_getIntercept();
    } else {
      this.intercept = null;
    }
  }
  @SuppressWarnings("unchecked")
  public PersistRequestBean(
      SpiEbeanServer server,
      T bean,
      Object parentBean,
      BeanManager<T> mgr,
      SpiTransaction t,
      PersistExecute persistExecute) {

    super(server, t, persistExecute);
    this.beanManager = mgr;
    this.beanDescriptor = mgr.getBeanDescriptor();
    this.beanPersistListener = beanDescriptor.getPersistListener();
    this.bean = bean;
    this.parentBean = parentBean;

    this.controller = beanDescriptor.getPersistController();
    this.concurrencyMode = beanDescriptor.getConcurrencyMode();

    if (bean instanceof EntityBean) {
      this.intercept = ((EntityBean) bean)._ebean_getIntercept();
      if (intercept.isReference()) {
        // allowed to delete reference objects
        // with no concurrency checking
        this.concurrencyMode = ConcurrencyMode.NONE;
      }
      // this is ok to not use isNewOrDirty() as used for updates only
      this.isDirty = intercept.isDirty();
      if (!isDirty) {
        this.changedProps = intercept.getChangedProps();
      } else {
        // merge changed properties on the bean with changed embedded beans
        Set<String> beanChangedProps = intercept.getChangedProps();
        Set<String> dirtyEmbedded = beanDescriptor.getDirtyEmbeddedProperties(bean);
        this.changedProps = mergeChangedProperties(beanChangedProps, dirtyEmbedded);
      }
      this.loadedProps = intercept.getLoadedProps();
      this.oldValues = (T) intercept.getOldValues();
      this.vanilla = false;

    } else {
      // have to assume the vanilla bean is dirty
      this.vanilla = true;
      this.isDirty = true;
      this.loadedProps = null;
      this.changedProps = null;
      this.intercept = null;

      // degrade concurrency checking to none for vanilla bean
      if (concurrencyMode.equals(ConcurrencyMode.ALL)) {
        this.concurrencyMode = ConcurrencyMode.NONE;
      }
    }
  }
 /**
  * Create a GenerateDmlRequest used to generate the DML.
  *
  * <p>Will used changed properties or loaded properties depending on the
  * BeanDescriptor.isUpdateChangesOnly() value.
  */
 public GenerateDmlRequest createGenerateDmlRequest(boolean emptyStringAsNull) {
   if (beanDescriptor.isUpdateChangesOnly()) {
     return new GenerateDmlRequest(emptyStringAsNull, changedProps, loadedProps, oldValues);
   } else {
     return new GenerateDmlRequest(emptyStringAsNull, loadedProps, loadedProps, oldValues);
   }
 }
  /** Allocate the property to a list. */
  private void allocateToList(BeanProperty prop) {
    if (prop.isTransient()) {
      transients.add(prop);
      if (prop.isDraft()) {
        draft = prop;
      }
      return;
    }
    if (prop.isId()) {
      ids.add(prop);
      return;
    } else {
      nonTransients.add(prop);
    }

    if (prop.isMutableScalarType()) {
      mutable.add(prop);
    }

    if (desc.getInheritInfo() != null && prop.isLocal()) {
      local.add(prop);
    }

    if (prop instanceof BeanPropertyAssocMany<?>) {
      manys.add((BeanPropertyAssocMany<?>) prop);

    } else {
      nonManys.add(prop);
      if (prop instanceof BeanPropertyAssocOne<?>) {
        BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>) prop;
        if (prop.isEmbedded()) {
          embedded.add(assocOne);
        } else {
          ones.add(assocOne);
          if (!assocOne.isOneToOneExported()) {
            onesImported.add(assocOne);
          }
        }
      } else {
        // its a "base" property...
        if (prop.isVersion()) {
          if (versionProperty == null) {
            versionProperty = prop;
          } else {
            logger.warn(
                "Multiple @Version properties - property "
                    + prop.getFullBeanName()
                    + " not treated as a version property");
          }
        } else if (prop.isDraftDirty()) {
          draftDirty = prop;
        }
        if (prop instanceof BeanPropertyCompound) {
          baseCompound.add((BeanPropertyCompound) prop);
        } else {
          baseScalar.add(prop);
        }
      }
    }
  }
 public void notifyCache() {
   if (notifyCache) {
     switch (type) {
       case INSERT:
         beanDescriptor.cacheInsert(idValue, this);
         break;
       case UPDATE:
         beanDescriptor.cacheUpdate(idValue, this);
         break;
       case DELETE:
         beanDescriptor.cacheDelete(idValue, this);
         break;
       default:
         throw new IllegalStateException("Invalid type " + type);
     }
   }
 }
  /**
   * Setup the load context at this path with OrmQueryProperties which is used to build the
   * appropriate query for +query or +lazy loading.
   */
  private void registerSecondaryQuery(OrmQueryProperties props) {

    String propName = props.getPath();
    ElPropertyValue elGetValue = rootDescriptor.getElGetValue(propName);

    boolean many = elGetValue.getBeanProperty().containsMany();
    registerSecondaryNode(many, props);
  }
  /** Generate and bind the insert statement. */
  @Override
  public void bind() throws SQLException {

    BeanDescriptor<?> desc = persistRequest.getBeanDescriptor();
    EntityBean bean = persistRequest.getEntityBean();

    Object idValue = desc.getId(bean);

    boolean withId = !DmlUtil.isNullOrZero(idValue);

    // check to see if we are going to use generated keys
    if (!withId) {
      if (concatinatedKey) {
        // expecting a concatenated key that can
        // be built from supplied AssocOne beans
        withId = meta.deriveConcatenatedId(persistRequest);

      } else if (meta.supportsGetGeneratedKeys()) {
        // Identity with getGeneratedKeys
        useGeneratedKeys = true;
      } else {
        // use a query to get the last inserted id
        selectLastInsertedId = meta.getSelectLastInsertedId();
      }
    }

    SpiTransaction t = persistRequest.getTransaction();

    // get the appropriate sql
    sql = meta.getSql(withId);

    PreparedStatement pstmt;
    if (persistRequest.isBatched()) {
      pstmt = getPstmt(t, sql, persistRequest, useGeneratedKeys);
    } else {
      pstmt = getPstmt(t, sql, useGeneratedKeys);
    }
    dataBind = new DataBind(pstmt);

    // bind the bean property values
    meta.bind(this, bean, withId);

    logSql(sql);
  }
 /** Set the type of this request. One of INSERT, UPDATE, DELETE, UPDATESQL or CALLABLESQL. */
 @Override
 public void setType(Type type) {
   this.type = type;
   notifyCache = beanDescriptor.isCacheNotify();
   if (type == Type.DELETE || type == Type.UPDATE) {
     if (oldValues == null) {
       oldValues = bean;
     }
   }
 }
  /** Set the generated key back to the bean. Only used for inserts with getGeneratedKeys. */
  public void setGeneratedKey(Object idValue) {
    if (idValue != null) {

      // set back to the bean so that we can use the same bean later
      // for update [refer ebeanIntercept.setLoaded(true)].
      idValue = beanDescriptor.convertSetId(idValue, bean);

      // remember it for logging summary
      this.idValue = idValue;
    }
  }
 /**
  * The hash used to register the bean with the transaction.
  *
  * <p>Takes into account the class type and id value.
  */
 private Integer getBeanHash() {
   if (beanHash == null) {
     Object id = beanDescriptor.getId(bean);
     int hc = 31 * bean.getClass().getName().hashCode();
     if (id != null) {
       hc += id.hashCode();
     }
     beanHash = Integer.valueOf(hc);
   }
   return beanHash;
 }
  protected void executeDerivedRelationships() {
    List<DerivedRelationshipData> derivedRelationships = persistRequest.getDerivedRelationships();
    if (derivedRelationships != null) {

      SpiEbeanServer ebeanServer = (SpiEbeanServer) persistRequest.getEbeanServer();

      for (int i = 0; i < derivedRelationships.size(); i++) {
        DerivedRelationshipData derivedRelationshipData = derivedRelationships.get(i);

        BeanDescriptor<?> beanDescriptor =
            ebeanServer.getBeanDescriptor(derivedRelationshipData.getBean().getClass());

        BeanProperty prop =
            beanDescriptor.getBeanProperty(derivedRelationshipData.getLogicalName());
        EntityBean entityBean = (EntityBean) derivedRelationshipData.getBean();
        entityBean._ebean_getIntercept().markPropertyAsChanged(prop.getPropertyIndex());

        ebeanServer.update(entityBean, transaction);
      }
    }
  }
  /**
   * Add the bean to the collection passed.
   *
   * @param bean the bean to add
   * @param collection the collection or map to add the bean to
   */
  @SuppressWarnings({"unchecked", "rawtypes"})
  public void add(EntityBean bean, Object collection) {
    if (bean == null) {
      return;
    }
    rowCount++;
    if (isMap) {
      Object keyValue;
      if (mapKey != null) {
        // use the value for the property
        keyValue = desc.getValue(bean, mapKey);
      } else {
        // use the uniqueId for this
        keyValue = desc.getId(bean);
      }

      Map mapColl = (Map) collection;
      mapColl.put(keyValue, bean);
    } else {
      ((Collection) collection).add(bean);
    }
  }
 /**
  * Determine the concurrency mode depending on fully/partially populated bean.
  *
  * <p>Specifically with version concurrency we want to check that the version property was one of
  * the loaded properties.
  */
 public ConcurrencyMode determineConcurrencyMode() {
   if (loadedProps != null) {
     // 'partial bean' update/delete...
     if (concurrencyMode.equals(ConcurrencyMode.VERSION)) {
       // check the version property was loaded
       BeanProperty prop = beanDescriptor.firstVersionProperty();
       if (prop != null && loadedProps.contains(prop.getName())) {
         // OK to use version property
       } else {
         concurrencyMode = ConcurrencyMode.NONE;
       }
     }
   }
   return concurrencyMode;
 }
  /** Return a summary description of this query. */
  public String getSummary() {
    StringBuilder sb = new StringBuilder(80);
    sb.append("FindIds exeMicros[")
        .append(executionTimeMicros)
        .append("] rows[")
        .append(rowCount)
        .append("] type[")
        .append(desc.getName())
        .append("] predicates[")
        .append(predicates.getLogWhereSql())
        .append("] bind[")
        .append(bindLog)
        .append("]");

    return sb.toString();
  }
  private void logSummary() {

    String name = beanDescriptor.getName();
    switch (type) {
      case INSERT:
        transaction.logInternal("Inserted [" + name + "] [" + idValue + "]");
        break;
      case UPDATE:
        transaction.logInternal("Updated [" + name + "] [" + idValue + "]");
        break;
      case DELETE:
        transaction.logInternal("Deleted [" + name + "] [" + idValue + "]");
        break;
      default:
        break;
    }
  }
 public void setLoadedState() {
   if (ebi != null) {
     // takes into account reference beans
     beanDescriptor.setLoadedProps(ebi, loadedProps);
   }
 }
  /** There is a many property so we need to make sure the ordering is appropriate. */
  private String deriveOrderByWithMany(BeanPropertyAssocMany<?> manyProp) {

    if (manyProp == null) {
      return parseOrderBy();
    }

    String orderBy = parseOrderBy();

    BeanDescriptor<?> desc = request.getBeanDescriptor();
    String orderById = desc.getDefaultOrderBy();

    if (orderBy == null) {
      orderBy = orderById;
    }

    // check for default ordering on the many property...
    String manyOrderBy = manyProp.getFetchOrderBy();
    if (manyOrderBy != null) {
      orderBy = orderBy + ", " + CQueryBuilder.prefixOrderByFields(manyProp.getName(), manyOrderBy);
    }

    if (request.isFindById()) {
      // only one master bean so should be fine...
      return orderBy;
    }

    if (orderBy.startsWith(orderById)) {
      return orderBy;
    }

    // more than one top level row may be returned so
    // we need to make sure their is an order by on the
    // top level first (to ensure master/detail construction).

    int manyPos = orderBy.indexOf(manyProp.getName());
    int idPos = orderBy.indexOf(" " + orderById);

    if (manyPos == -1) {
      // no ordering of the many
      if (idPos == -1) {
        // append the orderById so that master level objects are ordered
        // even if the orderBy is not unique for the master object
        return orderBy + ", " + orderById;
      }
      // orderById is already in the order by clause
      return orderBy;
    }

    if (idPos <= -1 || idPos >= manyPos) {
      if (idPos > manyPos) {
        // there was an error with the order by...
        String msg =
            "A Query on ["
                + desc
                + "] includes a join to a 'many' association ["
                + manyProp.getName();
        msg += "] with an incorrect orderBy [" + orderBy + "]. The id property [" + orderById + "]";
        msg += " must come before the many property [" + manyProp.getName() + "] in the orderBy.";
        msg += " Ebean has automatically modified the orderBy clause to do this.";

        logger.warn(msg);
      }

      // the id needs to come before the manyPropName
      orderBy = orderBy.substring(0, manyPos) + orderById + ", " + orderBy.substring(manyPos);
    }

    return orderBy;
  }
 /**
  * Return true if the update DML/SQL must be dynamically generated.
  *
  * <p>This is the case for updates/deletes of partially populated beans.
  */
 public boolean isDynamicUpdateSql() {
   return !vanilla && beanDescriptor.isUpdateChangesOnly() || (loadedProps != null);
 }
 /** Validate the bean. This is not recursive and only runs the 'local' validation rules. */
 public void validate() {
   InvalidValue errs = beanDescriptor.validate(false, bean);
   if (errs != null) {
     throw new ValidationException(errs);
   }
 }
 /** Return the Id value for the bean. */
 public Object getBeanId() {
   return beanDescriptor.getId(bean);
 }
 /**
  * Returns a description of the request. This is typically the bean class name or the base table
  * for MapBeans.
  *
  * <p>Used to determine common persist requests for queueing and statement batching.
  */
 public String getFullName() {
   return beanDescriptor.getFullName();
 }
  /** Execute the query returning the row count. */
  public BeanIdList findIds() throws SQLException {

    long startNano = System.nanoTime();

    try {
      // get the list that we are going to put the id's into.
      // This was already set so that it is available to be
      // read by other threads (it is a synchronised list)
      List<Object> idList = query.getIdList();
      if (idList == null) {
        // running in foreground thread (not FutureIds query)
        idList = Collections.synchronizedList(new ArrayList<Object>());
        query.setIdList(idList);
      }

      BeanIdList result = new BeanIdList(idList);

      SpiTransaction t = request.getTransaction();
      Connection conn = t.getInternalConnection();
      pstmt = conn.prepareStatement(sql);

      if (query.getBufferFetchSizeHint() > 0) {
        pstmt.setFetchSize(query.getBufferFetchSizeHint());
      }

      if (query.getTimeout() > 0) {
        pstmt.setQueryTimeout(query.getTimeout());
      }

      bindLog = predicates.bind(new DataBind(pstmt));

      ResultSet rset = pstmt.executeQuery();
      dataReader = new RsetDataReader(rset);

      boolean hitMaxRows = false;
      boolean hasMoreRows = false;
      rowCount = 0;

      DbReadContext ctx = new DbContext();

      while (rset.next()) {
        Object idValue = desc.getIdBinder().read(ctx);
        idList.add(idValue);
        // reset back to 0
        dataReader.resetColumnPosition();
        rowCount++;

        if (maxRows > 0 && rowCount == maxRows) {
          hitMaxRows = true;
          hasMoreRows = rset.next();
          break;
        }
      }

      if (hitMaxRows) {
        result.setHasMore(hasMoreRows);
      }

      long exeNano = System.nanoTime() - startNano;
      executionTimeMicros = (int) exeNano / 1000;

      return result;

    } finally {
      close();
    }
  }
  private BeanProperty getBeanProperty(BeanDescriptor<?> desc, String path) {

    return desc.getBeanPropertyFromPath(path);
  }