/*
* eGov suite of products aim to improve the internal efficiency,transparency,
* accountability and the service delivery of the government organizations.
*
* Copyright (C) <2015> eGovernments Foundation
*
* The updated version of eGov suite of products as by eGovernments Foundation
* is available at http://www.egovernments.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/ or
* http://www.gnu.org/licenses/gpl.html .
*
* In addition to the terms of the GPL license to be adhered to in using this
* program, the following additional terms are to be complied with:
*
* 1) All versions of this program, verbatim or modified must carry this
* Legal Notice.
*
* 2) Any misrepresentation of the origin of the material is prohibited. It
* is required that all modified versions of this material be marked in
* reasonable ways as different from the original version.
*
* 3) This license does not grant any rights to any user of the program
* with regards to rights under trademark law for use of the trade names
* or trademarks of eGovernments Foundation.
*
* In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org.
*/
package org.egov.infra.workflow.service;
import org.egov.infra.exception.ApplicationRuntimeException;
import org.egov.infra.script.entity.Script;
import org.egov.infra.script.service.ScriptService;
import org.egov.infra.utils.StringUtils;
import org.egov.infra.workflow.entity.StateAware;
import org.egov.infra.workflow.entity.WorkflowAction;
import org.egov.infra.workflow.matrix.entity.WorkFlowMatrix;
import org.egov.infstr.services.PersistenceService;
import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
*
* This is a generic bean so do not use this to do transition of your own StateAware objects<br/>
* For your own StateAware object transition declare a separate bean definition
* like<br/>
* <pre>
* <bean id="myStateAwareWorkflowService" parent="workflowService">
* <constructor-arg index="0" ref="myStateAwarePersistenceService"/>
* </bean>
* </pre>
**/
@SuppressWarnings("unchecked")
public class SimpleWorkflowService<T extends StateAware> implements WorkflowService<T> {
private final PersistenceService<T, Long> stateAwarePersistenceService;
@Autowired
private WorkflowActionService workflowActionService;
@Autowired
private ScriptService scriptService;
public SimpleWorkflowService(final PersistenceService<T, Long> stateAwarePersistenceService) {
this.stateAwarePersistenceService = stateAwarePersistenceService;
}
@Override
public T transition(final WorkflowAction workflowAction, final T stateAware, final String comments) {
scriptService.executeScript(getScript(stateAware, workflowAction.getName()), ScriptService.createContext("action", this,
"wfItem", stateAware, "persistenceService", this.stateAwarePersistenceService, "workflowService", this,
"comments", comments));
return this.stateAwarePersistenceService.persist(stateAware);
}
@Override
public T transition(final String actionName, final T stateAware, final String comment) {
WorkflowAction workflowAction = workflowActionService.getWorkflowActionByNameAndType(actionName, stateAware.getStateType());
if (workflowAction == null)
workflowAction = new WorkflowAction(actionName, stateAware.getStateType(), actionName);
return transition(workflowAction, stateAware, comment);
}
@Override
public List<WorkflowAction> getValidActions(final T stateAware) {
final String scriptName = stateAware.getStateType() + ".workflow.validactions";
final Script trasitionScript = this.scriptService.getByName(scriptName);
final List<String> actionNames = (List<String>) scriptService.executeScript(trasitionScript,
ScriptService.createContext("wfItem", stateAware, "workflowService", this, "persistenceService",
this.stateAwarePersistenceService));
final List<WorkflowAction> savedWorkflowActions = workflowActionService.getAllWorkflowActionByTypeAndActionNames(stateAware.getStateType(), actionNames);
return savedWorkflowActions.isEmpty() ? createActions(stateAware, actionNames) : savedWorkflowActions;
}
public Object execute(final T stateAware) {
final Script script = getScript(stateAware, "");
return scriptService.executeScript(script, ScriptService.createContext("action", this, "wfItem", stateAware,
"persistenceService", this.stateAwarePersistenceService));
}
public Object execute(final T stateAware, final String comments) {
final Script script = getScript(stateAware, "");
return scriptService.executeScript(script, ScriptService.createContext("action", this, "wfItem", stateAware,
"persistenceService", this.stateAwarePersistenceService, "comments", comments));
}
private Script getScript(final T stateAware, final String actionName) {
Script script = null;
if(!actionName.isEmpty())
script = this.scriptService.getByName(stateAware.getStateType()+ ".workflow." + actionName);
if (script == null)
script = scriptService.getByName(stateAware.getStateType()+ ".workflow");
if (script == null)
throw new ApplicationRuntimeException("workflow.script.notfound");
return script;
}
private List<WorkflowAction> createActions(final T stateAware, final List<String> actionNames) {
final List<WorkflowAction> workflowActions = new ArrayList<>();
for (final String action : actionNames)
workflowActions.add(new WorkflowAction(action, stateAware.getStateType(), action));
return workflowActions;
}
@Override
public WorkFlowMatrix getWfMatrix(final String type, final String department, final BigDecimal amountRule,
final String additionalRule, final String currentState, final String pendingActions) {
final Criteria wfMatrixCriteria = createWfMatrixAdditionalCriteria(type, department, amountRule,
additionalRule, currentState, pendingActions);
return getWorkflowMatrixObj(type, additionalRule, currentState, pendingActions, wfMatrixCriteria);
}
@Override
public WorkFlowMatrix getWfMatrix(final String type, final String department, final BigDecimal amountRule,
final String additionalRule, final String currentState, final String pendingActions, Date date) {
final Criteria wfMatrixCriteria = createWfMatrixAdditionalCriteria(type, department, amountRule,
additionalRule, currentState, pendingActions);
final Criterion crit1 = Restrictions.le("fromDate", date == null ? new Date() : date);
final Criterion crit2 = Restrictions.ge("toDate", date == null ? new Date() : date);
final Criterion crit3 = Restrictions.conjunction().add(crit1).add(crit2);
wfMatrixCriteria.add(Restrictions.or(crit3, crit1));
return getWorkflowMatrixObj(type, additionalRule, currentState, pendingActions, wfMatrixCriteria);
}
private WorkFlowMatrix getWorkflowMatrixObj(final String type, final String additionalRule,
final String currentState, final String pendingActions, final Criteria wfMatrixCriteria) {
final List<WorkFlowMatrix> objectTypeList = wfMatrixCriteria.list();
if (objectTypeList.isEmpty()) {
final Criteria defaulfWfMatrixCriteria = commonWorkFlowMatrixCriteria(type, additionalRule, currentState,
pendingActions);
defaulfWfMatrixCriteria.add(Restrictions.eq("department", "ANY"));
final List<WorkFlowMatrix> defaultObjectTypeList = defaulfWfMatrixCriteria.list();
if (defaultObjectTypeList.isEmpty())
return null;
else
return defaultObjectTypeList.get(0);
} else {
for (final WorkFlowMatrix matrix : objectTypeList)
if (matrix.getToDate() == null)
return matrix;
return objectTypeList.get(0);
}
}
private Criteria createWfMatrixAdditionalCriteria(final String type, final String department,
final BigDecimal amountRule, final String additionalRule, final String currentState,
final String pendingActions) {
final Criteria wfMatrixCriteria = commonWorkFlowMatrixCriteria(type, additionalRule, currentState,
pendingActions);
if (department != null && !"".equals(department.trim()))
wfMatrixCriteria.add(Restrictions.eq("department", department));
// Added restriction for amount rule
if (amountRule != null && BigDecimal.ZERO.compareTo(amountRule) != 0) {
final Criterion amount1st = Restrictions.conjunction().add(Restrictions.le("fromQty", amountRule))
.add(Restrictions.ge("toQty", amountRule));
final Criterion amount2nd = Restrictions.conjunction().add(Restrictions.le("fromQty", amountRule))
.add(Restrictions.isNull("toQty"));
wfMatrixCriteria.add(Restrictions.disjunction().add(amount1st).add(amount2nd));
}
return wfMatrixCriteria;
}
public WorkFlowMatrix getPreviousStateFromWfMatrix(final String type, final String department, final BigDecimal amountRule,
final String additionalRule, final String currentState, final String pendingActions) {
final Criteria wfMatrixCriteria = previousWorkFlowMatrixCriteria(type,additionalRule, currentState, pendingActions);
if (department!=null && !"".equals(department)) {
wfMatrixCriteria.add(Restrictions.eq("department", department));
}else
wfMatrixCriteria.add(Restrictions.eq("department", "ANY"));
// Added restriction for amount rule
if (amountRule != null && BigDecimal.ZERO.compareTo(amountRule) != 0) {
final Criterion amount1st = Restrictions.conjunction()
.add(Restrictions.le("fromQty", amountRule))
.add(Restrictions.ge("toQty", amountRule));
final Criterion amount2nd = Restrictions.conjunction()
.add(Restrictions.le("fromQty", amountRule))
.add(Restrictions.isNull("toQty"));
wfMatrixCriteria.add(Restrictions.disjunction().add(amount1st)
.add(amount2nd));
}
final List<WorkFlowMatrix> objectTypeList = wfMatrixCriteria.list();
if (!objectTypeList.isEmpty()) {
return objectTypeList.get(0);
}
return null;
}
private Criteria previousWorkFlowMatrixCriteria(String type,String additionalRule,String currentState,String pendingActions){
final Criteria commonWfMatrixCriteria=this.stateAwarePersistenceService.getSession().createCriteria(WorkFlowMatrix.class);
commonWfMatrixCriteria.add(Restrictions.eq("objectType", type));
if(StringUtils.isNotBlank(additionalRule)){
commonWfMatrixCriteria.add(Restrictions.eq("additionalRule", additionalRule));
}
if(StringUtils.isNotBlank(pendingActions)){
commonWfMatrixCriteria.add(Restrictions.ilike("nextAction", pendingActions,MatchMode.EXACT));
}
if(StringUtils.isNotBlank(currentState)){
commonWfMatrixCriteria.add(Restrictions.ilike("nextState", currentState,MatchMode.EXACT));
}
return commonWfMatrixCriteria;
}
private Criteria commonWorkFlowMatrixCriteria(final String type, final String additionalRule,
final String currentState, final String pendingActions) {
final Criteria commonWfMatrixCriteria = this.stateAwarePersistenceService.getSession().createCriteria(
WorkFlowMatrix.class);
commonWfMatrixCriteria.add(Restrictions.eq("objectType", type));
if (additionalRule != null && !"".equals(additionalRule.trim()))
commonWfMatrixCriteria.add(Restrictions.eq("additionalRule", additionalRule));
if (pendingActions != null && !"".equals(pendingActions.trim()))
commonWfMatrixCriteria.add(Restrictions.ilike("pendingActions", pendingActions, MatchMode.ANYWHERE));
if (currentState != null && !"".equals(currentState.trim()))
commonWfMatrixCriteria.add(Restrictions.ilike("currentState", currentState, MatchMode.ANYWHERE));
else
commonWfMatrixCriteria.add(Restrictions.ilike("currentState", "NEW", MatchMode.ANYWHERE));
return commonWfMatrixCriteria;
}
}