Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/* 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.
*/
package org.activiti.engine.impl.db;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.ActivitiOptimisticLockingException;
import org.activiti.engine.ActivitiWrongDbException;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.delegate.event.ActivitiEventType;
import org.activiti.engine.delegate.event.ActivitiVariableEvent;
import org.activiti.engine.delegate.event.impl.ActivitiEventBuilder;
import org.activiti.engine.impl.DeploymentQueryImpl;
import org.activiti.engine.impl.ExecutionQueryImpl;
import org.activiti.engine.impl.GroupQueryImpl;
import org.activiti.engine.impl.HistoricActivityInstanceQueryImpl;
import org.activiti.engine.impl.HistoricDetailQueryImpl;
import org.activiti.engine.impl.HistoricProcessInstanceQueryImpl;
import org.activiti.engine.impl.HistoricTaskInstanceQueryImpl;
import org.activiti.engine.impl.HistoricVariableInstanceQueryImpl;
import org.activiti.engine.impl.JobQueryImpl;
import org.activiti.engine.impl.ModelQueryImpl;
import org.activiti.engine.impl.Page;
import org.activiti.engine.impl.ProcessDefinitionQueryImpl;
import org.activiti.engine.impl.ProcessInstanceQueryImpl;
import org.activiti.engine.impl.TaskQueryImpl;
import org.activiti.engine.impl.UserQueryImpl;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.db.upgrade.DbUpgradeStep;
import org.activiti.engine.impl.history.HistoryLevel;
import org.activiti.engine.impl.interceptor.Session;
import org.activiti.engine.impl.persistence.cache.CachedEntity;
import org.activiti.engine.impl.persistence.cache.EntityCache;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.PropertyEntity;
import org.activiti.engine.impl.persistence.entity.VariableInstanceEntity;
import org.activiti.engine.impl.util.IoUtil;
import org.activiti.engine.impl.util.ReflectUtil;
import org.activiti.engine.impl.variable.DeserializedObject;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* responsibilities: - delayed flushing of inserts updates and deletes - optional dirty checking - db specific statement name mapping
*
* @author Tom Baeyens
* @author Joram Barrez
*/
public class DbSqlSession implements Session {
private static final Logger log = LoggerFactory.getLogger(DbSqlSession.class);
protected static final Pattern CLEAN_VERSION_REGEX = Pattern.compile("\\d\\.\\d*");
protected static final List ACTIVITI_VERSIONS = new ArrayList();
static {
/* Previous */
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.7"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.8"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.9"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.10"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.11"));
// 5.12.1 was a bugfix release on 5.12 and did NOT change the version in ACT_GE_PROPERTY
// On top of that, DB2 create script for 5.12.1 was shipped with a 'T' suffix ...
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.12", Arrays.asList("5.12.1", "5.12T")));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.13"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.14"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.15"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.15.1"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.16"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.16.1"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.16.2-SNAPSHOT"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.16.2"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.16.3.0"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.16.4.0"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.17.0.0"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.17.0.1"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.17.0.2"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.18.0.0"));
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.18.0.1"));
// This is the latest version of the 5 branch. It's a 'virtual' version cause it doesn't exist, but it is
// there to make sure all previous version can upgrade to the 6 version correctly.
ACTIVITI_VERSIONS.add(new ActivitiVersion("5.99.0.0"));
// Version 6
ACTIVITI_VERSIONS.add(new ActivitiVersion("6.0.0.0"));
/* Current */
ACTIVITI_VERSIONS.add(new ActivitiVersion(ProcessEngine.VERSION));
}
protected SqlSession sqlSession;
protected DbSqlSessionFactory dbSqlSessionFactory;
protected EntityCache entityCache;
protected Map, List> insertedObjects = new HashMap, List>();
protected List deleteOperations = new ArrayList();
protected List deserializedObjects = new ArrayList();
protected String connectionMetadataDefaultCatalog;
protected String connectionMetadataDefaultSchema;
public DbSqlSession(DbSqlSessionFactory dbSqlSessionFactory, EntityCache entityCache) {
this.dbSqlSessionFactory = dbSqlSessionFactory;
this.sqlSession = dbSqlSessionFactory.getSqlSessionFactory().openSession();
this.entityCache = entityCache;
}
public DbSqlSession(DbSqlSessionFactory dbSqlSessionFactory, EntityCache entityCache, Connection connection, String catalog, String schema) {
this.dbSqlSessionFactory = dbSqlSessionFactory;
this.sqlSession = dbSqlSessionFactory.getSqlSessionFactory().openSession(connection); // Note the use of connection param here, different from other constructor
this.entityCache = entityCache;
this.connectionMetadataDefaultCatalog = catalog;
this.connectionMetadataDefaultSchema = schema;
}
// insert ///////////////////////////////////////////////////////////////////
public void insert(Entity entity) {
if (entity.getId() == null) {
String id = dbSqlSessionFactory.getIdGenerator().getNextId();
entity.setId(id);
}
Class extends Entity> clazz = entity.getClass();
if (!insertedObjects.containsKey(clazz)) {
insertedObjects.put(clazz, new ArrayList());
}
insertedObjects.get(clazz).add(entity);
entityCache.put(entity, false);
}
// update
// ///////////////////////////////////////////////////////////////////
public void update(Entity entity) {
entityCache.put(entity, false);
}
public int update(String statement, Object parameters) {
String updateStatement = dbSqlSessionFactory.mapStatement(statement);
return getSqlSession().update(updateStatement, parameters);
}
// delete
// ///////////////////////////////////////////////////////////////////
public void delete(String statement, Object parameter) {
deleteOperations.add(new BulkDeleteOperation(statement, parameter));
}
public void delete(Entity entity) {
for (DeleteOperation deleteOperation : deleteOperations) {
if (deleteOperation.sameIdentity(entity)) {
log.debug("skipping redundant delete: {}", entity);
return; // Skip this delete. It was already added.
}
}
deleteOperations.add(new CheckedDeleteOperation(entity));
}
public interface DeleteOperation {
/**
* @return The persistent object class that is being deleted.
* Null in case there are multiple objects of different types!
*/
Class extends Entity> getEntityClass();
boolean sameIdentity(Entity other);
void clearCache();
void execute();
}
/**
* Use this {@link DeleteOperation} to execute a dedicated delete statement. It is important to note there won't be any optimistic locking checks done for these kind of delete operations!
*
* For example, a usage of this operation would be to delete all variables for a certain execution, when that certain execution is removed. The optimistic locking happens on the execution, but the
* variables can be removed by a simple 'delete from var_table where execution_id is xxx'. It could very well be there are no variables, which would also work with this query, but not with the
* regular {@link CheckedDeleteOperation}.
*/
public class BulkDeleteOperation implements DeleteOperation {
private String statement;
private Object parameter;
public BulkDeleteOperation(String statement, Object parameter) {
this.statement = dbSqlSessionFactory.mapStatement(statement);
this.parameter = parameter;
}
@Override
public Class extends Entity> getEntityClass() {
return null;
}
@Override
public boolean sameIdentity(Entity other) {
// this implementation is unable to determine what the identity of
// the removed object(s) will be.
return false;
}
@Override
public void clearCache() {
// this implementation cannot clear the object(s) to be removed from the cache.
}
@Override
public void execute() {
sqlSession.delete(statement, parameter);
}
@Override
public String toString() {
return "bulk delete: " + statement + "(" + parameter + ")";
}
}
/**
* A {@link DeleteOperation} that checks for concurrent modifications if the persistent object implements {@link HasRevision}. That is, it employs optimisting concurrency control. Used when the
* persistent object has been fetched already.
*/
public class CheckedDeleteOperation implements DeleteOperation {
protected final Entity entity;
public CheckedDeleteOperation(Entity entity) {
this.entity = entity;
}
@Override
public Class extends Entity> getEntityClass() {
return entity.getClass();
}
@Override
public boolean sameIdentity(Entity other) {
return entity.getClass().equals(other.getClass()) && entity.getId().equals(other.getId());
}
@Override
public void clearCache() {
entityCache.cacheRemove(entity.getClass(), entity.getId());
}
public void execute() {
String deleteStatement = dbSqlSessionFactory.getDeleteStatement(entity.getClass());
deleteStatement = dbSqlSessionFactory.mapStatement(deleteStatement);
if (deleteStatement == null) {
throw new ActivitiException("no delete statement for " + entity.getClass() + " in the ibatis mapping files");
}
// It only makes sense to check for optimistic locking exceptions
// for objects that actually have a revision
if (entity instanceof HasRevision) {
int nrOfRowsDeleted = sqlSession.delete(deleteStatement, entity);
if (nrOfRowsDeleted == 0) {
throw new ActivitiOptimisticLockingException(entity + " was updated by another transaction concurrently");
}
} else {
sqlSession.delete(deleteStatement, entity);
}
}
public Entity getEntity() {
return entity;
}
@Override
public String toString() {
return "delete " + entity;
}
}
/**
* A bulk version of the {@link CheckedDeleteOperation}.
*/
public class BulkCheckedDeleteOperation implements DeleteOperation {
protected Class extends Entity> entityClass;
protected List entities = new ArrayList();
public BulkCheckedDeleteOperation(Class extends Entity> entityClass) {
this.entityClass = entityClass;
}
public void addEntity(Entity entity) {
entities.add(entity);
}
@Override
public boolean sameIdentity(Entity other) {
for (Entity entity : entities) {
if (entity.getClass().equals(other.getClass()) && entity.getId().equals(other.getId())) {
return true;
}
}
return false;
}
@Override
public void clearCache() {
for (Entity entity : entities) {
entityCache.cacheRemove(entity.getClass(), entity.getId());
}
}
public void execute() {
if (entities.isEmpty()) {
return;
}
String bulkDeleteStatement = dbSqlSessionFactory.getBulkDeleteStatement(entityClass);
bulkDeleteStatement = dbSqlSessionFactory.mapStatement(bulkDeleteStatement);
if (bulkDeleteStatement == null) {
throw new ActivitiException("no bulk delete statement for " + entityClass + " in the mapping files");
}
sqlSession.delete(bulkDeleteStatement, entities);
}
public Class extends Entity> getEntityClass() {
return entityClass;
}
public void setEntityClass(Class extends Entity> entityClass) {
this.entityClass = entityClass;
}
public List getEntities() {
return entities;
}
public void setEntities(List entities) {
this.entities = entities;
}
@SuppressWarnings("unchecked")
public void setEntityObjects(List extends Entity> entities) {
this.entities = (List) entities;
}
@Override
public String toString() {
return "bulk delete of " + entities.size() + (!entities.isEmpty() ? " entities of " + entities.get(0).getClass() : 0);
}
}
// select
// ///////////////////////////////////////////////////////////////////
@SuppressWarnings({ "rawtypes" })
public List selectList(String statement) {
return selectList(statement, null, 0, Integer.MAX_VALUE);
}
@SuppressWarnings("rawtypes")
public List selectList(String statement, Object parameter) {
return selectList(statement, parameter, 0, Integer.MAX_VALUE);
}
@SuppressWarnings("rawtypes")
public List selectList(String statement, Object parameter, Page page) {
if (page != null) {
return selectList(statement, parameter, page.getFirstResult(), page.getMaxResults());
} else {
return selectList(statement, parameter, 0, Integer.MAX_VALUE);
}
}
@SuppressWarnings("rawtypes")
public List selectList(String statement, ListQueryParameterObject parameter, Page page) {
return selectList(statement, parameter);
}
@SuppressWarnings("rawtypes")
public List selectList(String statement, Object parameter, int firstResult, int maxResults) {
return selectList(statement, new ListQueryParameterObject(parameter, firstResult, maxResults));
}
@SuppressWarnings("rawtypes")
public List selectList(String statement, ListQueryParameterObject parameter) {
return selectListWithRawParameter(statement, parameter, parameter.getFirstResult(), parameter.getMaxResults());
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public List selectListWithRawParameter(String statement, Object parameter, int firstResult, int maxResults) {
statement = dbSqlSessionFactory.mapStatement(statement);
if (firstResult == -1 || maxResults == -1) {
return Collections.EMPTY_LIST;
}
List loadedObjects = sqlSession.selectList(statement, parameter);
return filterLoadedObjects(loadedObjects);
}
@SuppressWarnings({ "rawtypes" })
public List selectListWithRawParameterWithoutFilter(String statement, Object parameter, int firstResult, int maxResults) {
statement = dbSqlSessionFactory.mapStatement(statement);
if (firstResult == -1 || maxResults == -1) {
return Collections.EMPTY_LIST;
}
return sqlSession.selectList(statement, parameter);
}
public Object selectOne(String statement, Object parameter) {
statement = dbSqlSessionFactory.mapStatement(statement);
Object result = sqlSession.selectOne(statement, parameter);
if (result instanceof Entity) {
Entity loadedObject = (Entity) result;
result = cacheFilter(loadedObject);
}
return result;
}
public T selectById(Class entityClass, String id) {
return selectById(entityClass, id, true);
}
@SuppressWarnings("unchecked")
public T selectById(Class entityClass, String id, boolean checkCache) {
T entity = null;
if (checkCache) {
entity = entityCache.findInCache(entityClass, id);
if (entity != null) {
return entity;
}
}
String selectStatement = dbSqlSessionFactory.getSelectStatement(entityClass);
selectStatement = dbSqlSessionFactory.mapStatement(selectStatement);
entity = (T) sqlSession.selectOne(selectStatement, id);
if (entity == null) {
return null;
}
entityCache.put(entity, true);
return entity;
}
// internal session cache
// ///////////////////////////////////////////////////
@SuppressWarnings("rawtypes")
protected List filterLoadedObjects(List