public Map<String, Long> getTableCount() {
   Map<String, Long> tableCount = new HashMap<String, Long>();
   try {
     for (String tableName : getDbEntityManager().getTableNamesPresentInDatabase()) {
       tableCount.put(tableName, getTableCount(tableName));
     }
     LOG.countRowsPerProcessEngineTable(tableCount);
   } catch (Exception e) {
     throw LOG.countTableRowsException(e);
   }
   return tableCount;
 }
 protected long getTableCount(String tableName) {
   LOG.selectTableCountForTable(tableName);
   Long count =
       (Long)
           getDbEntityManager()
               .selectOne("selectTableCount", Collections.singletonMap("tableName", tableName));
   return count;
 }
  protected void flushDbOperationManager() {
    // obtain totally ordered operation list from operation manager
    List<DbOperation> operationsToFlush = dbOperationManager.calculateFlush();
    LOG.databaseFlushSummary(operationsToFlush);

    // execute the flush
    for (DbOperation dbOperation : operationsToFlush) {
      try {
        persistenceSession.executeDbOperation(dbOperation);
      } catch (Exception e) {
        throw LOG.flushDbOperationException(operationsToFlush, dbOperation, e);
      }
      if (dbOperation.isFailed()) {
        handleOptimisticLockingException(dbOperation);
      }
    }
  }
  /**
   * Flushes the entity cache: Depending on the entity state, the required {@link DbOperation} is
   * performed and the cache is updated.
   */
  protected void flushEntityCache() {
    List<CachedDbEntity> cachedEntities = dbEntityCache.getCachedEntities();
    for (CachedDbEntity cachedDbEntity : cachedEntities) {
      flushCachedEntity(cachedDbEntity);
    }

    // log cache state after flush
    LOG.flushedCacheState(dbEntityCache.getCachedEntities());
  }
  public void merge(DbEntity dbEntity) {

    if (dbEntity.getId() == null) {
      throw LOG.mergeDbEntityException(dbEntity);
    }

    // NOTE: a proper implementation of merge() would fetch the entity from the database
    // and merge the state changes. For now, we simply always perform an update.
    // Supposedly, the "proper" implementation would reduce the number of situations where
    // optimistic locking results in a conflict.

    dbEntityCache.putMerged(dbEntity);
  }
  /**
   * @return the latest version of the decision definition with the given key (from any tenant)
   * @throws ProcessEngineException if more than one tenant has a decision definition with the given
   *     key
   * @see #findLatestDecisionDefinitionByKeyAndTenantId(String, String)
   */
  public DecisionDefinitionEntity findLatestDecisionDefinitionByKey(String decisionDefinitionKey) {
    @SuppressWarnings("unchecked")
    List<DecisionDefinitionEntity> decisionDefinitions =
        getDbEntityManager()
            .selectList("selectLatestDecisionDefinitionByKey", decisionDefinitionKey);

    if (decisionDefinitions.isEmpty()) {
      return null;

    } else if (decisionDefinitions.size() == 1) {
      return decisionDefinitions.iterator().next();

    } else {
      throw LOG.multipleTenantsForDecisionDefinitionKeyException(decisionDefinitionKey);
    }
  }
  protected void handleOptimisticLockingException(DbOperation dbOperation) {
    boolean isHandled = false;

    if (optimisticLockingListeners != null) {
      for (OptimisticLockingListener optimisticLockingListener : optimisticLockingListeners) {
        if (optimisticLockingListener.getEntityType() == null
            || optimisticLockingListener
                .getEntityType()
                .isAssignableFrom(dbOperation.getEntityType())) {
          optimisticLockingListener.failedOperation(dbOperation);
          isHandled = true;
        }
      }
    }

    if (!isHandled) {
      throw LOG.concurrentUpdateDbEntityException(dbOperation);
    }
  }
  public TableMetaData getTableMetaData(String tableName) {
    TableMetaData result = new TableMetaData();
    ResultSet resultSet = null;

    try {
      try {
        result.setTableName(tableName);
        DatabaseMetaData metaData = getDbSqlSession().getSqlSession().getConnection().getMetaData();

        if (DbSqlSessionFactory.POSTGRES.equals(
            getDbSqlSession().getDbSqlSessionFactory().getDatabaseType())) {
          tableName = tableName.toLowerCase();
        }

        resultSet = metaData.getColumns(null, null, tableName, null);
        while (resultSet.next()) {
          String name = resultSet.getString("COLUMN_NAME").toUpperCase();
          String type = resultSet.getString("TYPE_NAME").toUpperCase();
          result.addColumnMetaData(name, type);
        }

      } catch (SQLException se) {
        throw se;
      } finally {
        if (resultSet != null) {
          resultSet.close();
        }
      }
    } catch (Exception e) {
      throw LOG.retrieveMetadataException(e);
    }

    if (result.getColumnNames().size() == 0) {
      // According to API, when a table doesn't exist, null should be returned
      result = null;
    }
    return result;
  }