package org.mifos.rest.approval.service;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import org.joda.time.DateTime;
import org.mifos.application.servicefacade.ApplicationContextProvider;
import org.mifos.rest.approval.dao.ApprovalDao;
import org.mifos.rest.approval.domain.ApprovalMethod;
import org.mifos.rest.approval.domain.ApprovalState;
import org.mifos.rest.approval.domain.MethodArgHolder;
import org.mifos.rest.approval.domain.RESTApprovalEntity;
import org.mifos.security.MifosUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.ConversionService;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@Transactional(rollbackFor=Exception.class)
public class StandardApprovalService implements ApprovalService {
public static final Logger LOG = LoggerFactory.getLogger(StandardApprovalService.class);
@Autowired
ApprovalDao approvalDao;
@Autowired
ConversionService conversionService;
private boolean skipCreate;
@Transactional(readOnly=true)
@Override
public RESTApprovalEntity getDetails(Long id) {
return approvalDao.getDetails(id);
}
@Transactional(readOnly=true)
@Override
public List<RESTApprovalEntity> getAllWaiting() {
return approvalDao.findByState(ApprovalState.WAITING);
}
@Transactional(readOnly=true)
@Override
public List<RESTApprovalEntity> getAllNotWaiting() {
return approvalDao.findByExcludingState(ApprovalState.WAITING);
}
@Transactional(noRollbackFor=RESTCallInterruptException.class)
@Override
public void create(ApprovalMethod method) throws Exception {
if(!skipCreate) {
RESTApprovalEntity entity = new RESTApprovalEntity();
entity.setApprovalMethod(method);
entity.setState(ApprovalState.WAITING);
entity.setCreatedBy(getCurrentUserId());
entity.setCreatedOn(new DateTime());
approvalDao.create(entity);
throw new RESTCallInterruptException(entity.getId());
}
}
@Transactional
@Override
public Object approve(Long id) throws Exception {
RESTApprovalEntity entity = approvalDao.getDetails(id);
ApprovalMethod am = entity.getApprovalMethod();
Object result = null;
try {
result = excuteMethod(am);
entity.setState(ApprovalState.APPROVED);
} catch (Exception e) {
skipCreate = false;
result = "Error : " + interceptError(e);
}
entity.setApprovedBy(getCurrentUserId());
entity.setApprovedOn(new DateTime());
approvalDao.update(entity);
return result;
}
private String interceptError(Exception e) {
LOG.error("Approval call failed ", e);
if(e instanceof InvocationTargetException) {
if(e.getCause() != null) {
if(e.getCause().getMessage() != null) {
return e.getCause().getMessage();
}
return "Check parameters";
}
}
return "System failed";
}
@Transactional
@Override
public void updateMethodContent(Long id, ApprovalMethod approvalMethod) throws Exception {
RESTApprovalEntity entity = approvalDao.getDetails(id);
if(entity.getState().equals(ApprovalState.WAITING)) {
entity.setApprovalMethod(approvalMethod);
approvalDao.update(entity);
}
}
@Transactional
@Override
public void reject(Long id) {
RESTApprovalEntity entity = approvalDao.getDetails(id);
entity.setApprovedBy(getCurrentUserId());
entity.setApprovedOn(new DateTime());
entity.setState(ApprovalState.REJECTED);
approvalDao.update(entity);
}
private Object excuteMethod(ApprovalMethod am) throws Exception {
Method m = am.getType().getMethod(am.getName(), am.getArgsHolder().getTypes());
skipCreate = true;
typeConversionCheck(am.getArgsHolder());
Object result = m.invoke(ApplicationContextProvider.getBean(am.getType()), am.getArgsHolder().getValues());
skipCreate = false;
return result;
}
private void typeConversionCheck(MethodArgHolder argsHolder) {
for(int i=0; i < argsHolder.getValues().length; i++) {
argsHolder.getValues()[i] = conversionService.convert(argsHolder.getValues()[i], argsHolder.getTypes()[i]);
}
}
private Short getCurrentUserId() {
MifosUser user = (MifosUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return (short) user.getUserId();
}
}