/*
* Copyright 2017 Red Hat, Inc. and/or its affiliates.
*
* 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.jbpm.runtime.manager.impl.error;
import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.function.Function;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.drools.persistence.api.TransactionManager;
import org.drools.persistence.api.TransactionManagerFactory;
import org.jbpm.runtime.manager.impl.jpa.ExecutionErrorInfo;
import org.kie.api.runtime.Environment;
import org.kie.api.runtime.EnvironmentName;
import org.kie.internal.runtime.error.ExecutionError;
import org.kie.internal.runtime.error.ExecutionErrorStorage;
public class DefaultExecutionErrorStorage implements ExecutionErrorStorage {
private static String SPRING_TM_CLASSNAME = "org.springframework.transaction.support.AbstractPlatformTransactionManager";
private static String KIE_SPRING_TM_CLASSNAME = "org.kie.spring.persistence.KieSpringTransactionManager";
private EntityManagerFactory emf;
private TransactionManager txm;
public DefaultExecutionErrorStorage(Environment environment) {
this.emf = (EntityManagerFactory) environment.get(EnvironmentName.ENTITY_MANAGER_FACTORY);
// if there is no entity manager factory, running with in memory settings so error handling is deactivated
if (this.emf != null) {
this.txm = getTransactionManager(environment);
}
}
@Override
public ExecutionError store(ExecutionError error) {
if (!isActive()) {
return error;
}
return call((EntityManager em) -> {
ExecutionErrorInfo errorEntity = new ExecutionErrorInfo(
error.getErrorId(),
error.getType(),
error.getDeploymentId(),
error.getProcessInstanceId(),
error.getProcessId(),
error.getActivityId(),
error.getActivityName(),
error.getJobId(),
error.getErrorMessage(),
error.getError(),
error.getErrorDate()
);
em.persist(errorEntity);
return error;
});
}
@SuppressWarnings("unchecked")
@Override
public List<ExecutionError> list(Integer page, Integer pageSize) {
if (!isActive()) {
return Collections.EMPTY_LIST;
}
int startPosition = page * pageSize;
return call((EntityManager em) -> {
return em.createQuery("from ExecutionErrorInfo")
.setFirstResult(startPosition)
.setMaxResults(pageSize)
.getResultList();
});
}
@Override
public ExecutionError get(String errorId) {
if (!isActive()) {
return null;
}
return (ExecutionError) call((EntityManager em) -> {
return em.createQuery("from ExecutionErrorInfo where errorId =:errorId")
.setParameter("errorId", errorId)
.getSingleResult();
});
}
@Override
public void acknowledge(final String user, final String...errorIds) {
if (!isActive()) {
return;
}
call((EntityManager em) -> {
for (String errorId : errorIds) {
ExecutionError error = (ExecutionError) em.createQuery("from ExecutionErrorInfo where errorId =:errorId")
.setParameter("errorId", errorId)
.getSingleResult();
error.setAcknowledged(true);
error.setAcknowledgedBy(user);
error.setAcknowledgedAt(new Date());
em.merge(error);
}
return null;
});
}
@SuppressWarnings("unchecked")
@Override
public List<ExecutionError> listByProcessInstance(Long processInstanceId, Integer page, Integer pageSize) {
if (!isActive()) {
return Collections.EMPTY_LIST;
}
int startPosition = page * pageSize;
return call((EntityManager em) -> {
return em.createQuery("from ExecutionErrorInfo where processInstanceId =:processInstanceId")
.setParameter("processInstanceId", processInstanceId)
.setFirstResult(startPosition)
.setMaxResults(pageSize)
.getResultList();
});
}
@SuppressWarnings("unchecked")
@Override
public List<ExecutionError> listByActivity(String activityName, Integer page, Integer pageSize) {
if (!isActive()) {
return Collections.EMPTY_LIST;
}
int startPosition = page * pageSize;
return call((EntityManager em) -> {
return em.createQuery("from ExecutionErrorInfo where activityName =:activityName")
.setParameter("activityName", activityName)
.setFirstResult(startPosition)
.setMaxResults(pageSize)
.getResultList();
});
}
@SuppressWarnings("unchecked")
@Override
public List<ExecutionError> listByDeployment(String deploymentId, Integer page, Integer pageSize) {
if (!isActive()) {
return Collections.EMPTY_LIST;
}
int startPosition = page * pageSize;
return call((EntityManager em) -> {
return em.createQuery("from ExecutionErrorInfo where deploymentId =:deploymentId")
.setParameter("deploymentId", deploymentId)
.setFirstResult(startPosition)
.setMaxResults(pageSize)
.getResultList();
});
}
/*
* Helper methods
*/
protected <R> R call(Function<EntityManager, R> function) {
boolean transactionOwner = false;
try {
transactionOwner = txm.begin();
EntityManager em = emf.createEntityManager();
R result = function.apply(em);
txm.commit( transactionOwner );
em.close();
return result;
} catch (Exception e) {
txm.rollback(transactionOwner);
throw new RuntimeException( "Exception when persisting error information", e);
}
}
protected TransactionManager getTransactionManager(Environment environment) {
Object tx = environment.get(EnvironmentName.TRANSACTION_MANAGER);
if (tx != null) {
if (tx instanceof TransactionManager) {
return (TransactionManager) tx;
} if (isSpringTransactionManager(tx.getClass())) {
try {
Class< ? > cls = Class.forName(KIE_SPRING_TM_CLASSNAME);
Constructor< ? > con = cls.getConstructors()[0];
return (TransactionManager) con.newInstance( tx );
} catch (Exception e) {
throw new RuntimeException("Not possible to create spring transaction manager", e);
}
}
}
return TransactionManagerFactory.get().newTransactionManager(environment);
}
protected boolean isSpringTransactionManager( Class<?> clazz ) {
if ( SPRING_TM_CLASSNAME.equals(clazz.getName()) ) {
return true;
}
// Try to find from the ancestors
if (clazz.getSuperclass() != null)
{
return isSpringTransactionManager(clazz.getSuperclass());
}
return false;
}
protected boolean isActive() {
if (this.emf != null && this.txm != null) {
return true;
}
return false;
}
}