/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * Copyright (c) 2013, MPL CodeInside http://codeinside.ru */ package ru.codeinside.gses.manager; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableList; import com.vaadin.addon.jpacontainer.filter.util.AdvancedFilterableSupport; import com.vaadin.data.Container; import com.vaadin.data.util.filter.Between; import com.vaadin.data.util.filter.Compare; import com.vaadin.data.util.filter.SimpleStringFilter; import org.activiti.engine.repository.ProcessDefinition; import org.apache.commons.lang.StringUtils; import ru.codeinside.adm.database.DefinitionStatus; import ru.codeinside.adm.database.Employee; import ru.codeinside.adm.database.Procedure; import ru.codeinside.adm.database.ProcedureProcessDefinition; import ru.codeinside.adm.database.ProcedureType; import ru.codeinside.adm.database.Service; import ru.codeinside.adm.parser.ServiceFixtureParser; import ru.codeinside.gses.webui.Flash; import javax.ejb.DependsOn; import javax.ejb.EJBException; import javax.ejb.Lock; import javax.ejb.LockType; import javax.ejb.Singleton; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionManagement; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; import java.io.IOException; import java.io.InputStream; import java.sql.Timestamp; import java.text.DecimalFormat; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; @TransactionManagement @TransactionAttribute @Singleton @DependsOn("BaseBean") @Lock(LockType.READ) public class ManagerService { @PersistenceContext(unitName = "myPU") EntityManager em; /** * Внимание! Не может регистрировать сам себя! */ transient static ManagerService instance; public static ManagerService get() { if (instance == null) { throw new IllegalStateException("Сервис не зарегистрирован!"); } return instance; } public Procedure createProcedure(String name, String description, String serviceId, Long code, String login, ProcedureType type) { try { if (hasProcedureWithSameRegisterCode(code)) { throw new RuntimeException("Процедура с таким кодом уже существует"); } final Procedure procedure = new Procedure(); mergeProcedure(procedure, name, description, serviceId, code, type); procedure.setCreator(em.find(Employee.class, login)); em.persist(procedure); return procedure; } catch (EJBException e) { final String message; if (e.getMessage() != null) { message = e.getMessage(); } else if (e.getCausedByException() != null) { message = e.getCausedByException().getMessage(); } else { message = e.getCause() != null ? e.getCause().getMessage() : e.getClass().toString(); } throw new RuntimeException(message); } } private void mergeProcedure(final Procedure procedure, String name, String description, String serviceId, Long code, ProcedureType type) { procedure.setName(name); procedure.setDescription(description); if (serviceId != null) { procedure.setService(em.find(Service.class, Long.parseLong(serviceId))); } if (type != null) { procedure.setType(type); } procedure.setRegisterCode(code); } private boolean hasProcedureWithSameRegisterCode(Long code) { if (code == null) { return false; } int countWithCode = em.createQuery("select p from Procedure p where p.registerCode=:registerCode ", Procedure.class).setParameter("registerCode", code).getResultList().size(); return countWithCode != 0; } private boolean hasServiceWithSameRegisterCode(Long code) { if (code == null) { return false; } return em.createQuery("select count(p) from Service p where p.registerCode=:registerCode ", Long.class).setParameter("registerCode", code).getSingleResult() > 0; } public void updateProcedure(String id, String name, String description, String serviceId, Long code) { Procedure procedure = em.find(Procedure.class, Long.parseLong(id)); if (code != null && !code.equals(procedure.getRegisterCode()) && hasProcedureWithSameRegisterCode(code)) { throw new RuntimeException("Процедура с таким кодом уже существует"); } mergeProcedure(procedure, name, description, serviceId, code, null); em.persist(procedure); } public void updateProcedure(Long id, String name, Long code) { Procedure procedure = em.find(Procedure.class, id); if (code != null && !code.equals(procedure.getRegisterCode()) && hasProcedureWithSameRegisterCode(code)) { throw new RuntimeException("Процедура с таким кодом уже существует"); } mergeProcedure(procedure, name, procedure.getDescription(), null, code, null); em.persist(procedure); } public List<Procedure> findAllProcedures() { TypedQuery<Procedure> query = em.createNamedQuery("findAllProcedures", Procedure.class); return query.getResultList(); } public List<Service> findAllServices() { TypedQuery<Service> query = em.createNamedQuery("findAllServices", Service.class); return query.getResultList(); } public int getProcedureCount() { return em.createQuery("select count(p) from Procedure p", Number.class).getSingleResult().intValue(); } public List<Procedure> getProcedures(int start, int count, String[] order, boolean[] asc, ProcedureType type, AdvancedFilterableSupport newSender) { StringBuilder q = new StringBuilder("select p from Procedure p where p.type=:type"); Set<Timestamp> timestamps = null; if (newSender != null) { timestamps = procedureQueryFilters(newSender, q); } for (int i = 0; i < order.length; i++) { if (i == 0) { q.append(" order by "); } else { q.append(", "); } q.append("p.").append(order[i]).append(asc[i] ? " asc" : " desc"); } if (newSender != null) { Iterator<Timestamp> iterator = timestamps.iterator(); if (timestamps.size() == 1) { return em.createQuery(q.toString(), Procedure.class).setParameter("type", type).setParameter("value", iterator.next()).setFirstResult(start).setMaxResults(count).getResultList(); } else if (timestamps.size() == 2) { Timestamp next = iterator.next(); Timestamp next1 = iterator.next(); return em.createQuery(q.toString(), Procedure.class).setParameter("type", type).setParameter("startValue", next).setParameter("endValue", next1).setFirstResult(start).setMaxResults(count).getResultList(); } } return em.createQuery(q.toString(), Procedure.class).setParameter("type", type).setFirstResult(start).setMaxResults(count).getResultList(); } public List<Procedure> getProceduresByServiceId(Long serviceId, int start, int count, String[] order, boolean[] asc, AdvancedFilterableSupport newSender) { StringBuilder q = new StringBuilder("select p from Procedure p where p.service.id=:serviceId "); Set<Timestamp> timestamps = null; if (newSender != null) { timestamps = procedureQueryFilters(newSender, q); } for (int i = 0; i < order.length; i++) { if (i == 0) { q.append(" order by "); } else { q.append(", "); } q.append("p.").append(order[i]).append(asc[i] ? " asc" : " desc"); } if (newSender != null) { Iterator<Timestamp> iterator = timestamps.iterator(); if (timestamps.size() == 1) { return em.createQuery(q.toString(), Procedure.class).setParameter("serviceId", serviceId).setParameter("value", iterator.next()).setFirstResult(start).setMaxResults(count).getResultList(); } else if (timestamps.size() == 2) { Timestamp next = iterator.next(); Timestamp next1 = iterator.next(); return em.createQuery(q.toString(), Procedure.class).setParameter("serviceId", serviceId).setParameter("startValue", next).setParameter("endValue", next1).setFirstResult(start).setMaxResults(count).getResultList(); } } return em.createQuery(q.toString(), Procedure.class).setParameter("serviceId", serviceId).setFirstResult(start) .setMaxResults(count).getResultList(); } private Set<Timestamp> procedureQueryFilters(AdvancedFilterableSupport newSender, StringBuilder q) { Set result = new HashSet(); for (Container.Filter filter : newSender.getFilters()) { if (filter instanceof Between) { String field = ((Between) filter).getPropertyId().toString(); result.add(new Timestamp(((Date) ((Between) filter).getStartValue()).getTime())); result.add(new Timestamp(((Date) ((Between) filter).getEndValue()).getTime())); q.append(" and p." + field + " >= :startValue and p." + field + " <= :endValue"); } else if (filter instanceof Compare.GreaterOrEqual) { String field = ((Compare.GreaterOrEqual) filter).getPropertyId().toString(); result.add(new Timestamp(((Date) ((Compare.GreaterOrEqual) filter).getValue()).getTime())); q.append(" and p." + field + " >= :value"); } else if (filter instanceof Compare.LessOrEqual) { String field = ((Compare.LessOrEqual) filter).getPropertyId().toString(); result.add(new Timestamp(((Date) ((Compare.LessOrEqual) filter).getValue()).getTime())); q.append(" and p." + field + " <= :value"); } else { String field = ((SimpleStringFilter) filter).getPropertyId().toString(); String value = ((SimpleStringFilter) filter).getFilterString(); if (field.equals("name") || field.equals("description") || field.equals("status") || field.equals("version")) { q.append(" and lower(p." + field + ") LIKE '" + value + "%'"); } else if (field.equals("id")) { if (checkString(value)) { q.append(" and p." + field + " = '" + value + "'"); } } } } return result; } private Set<Timestamp> serviceQueryFilters(AdvancedFilterableSupport newSender, StringBuilder q) { Set result = new HashSet(); for (Container.Filter filter : newSender.getFilters()) { if (filter instanceof Between) { String field = ((Between) filter).getPropertyId().toString(); result.add(new Timestamp(((Date) ((Between) filter).getStartValue()).getTime())); result.add(new Timestamp(((Date) ((Between) filter).getEndValue()).getTime())); q.append(" where s." + field + " >= :startValue and s." + field + " <= :endValue"); } else if (filter instanceof Compare.GreaterOrEqual) { String field = ((Compare.GreaterOrEqual) filter).getPropertyId().toString(); result.add(new Timestamp(((Date) ((Compare.GreaterOrEqual) filter).getValue()).getTime())); q.append(" where s." + field + " >= :value"); } else if (filter instanceof Compare.LessOrEqual) { String field = ((Compare.LessOrEqual) filter).getPropertyId().toString(); result.add(new Timestamp(((Date) ((Compare.LessOrEqual) filter).getValue()).getTime())); q.append(" where s." + field + " <= :value"); } else { String field = ((SimpleStringFilter) filter).getPropertyId().toString(); String value = ((SimpleStringFilter) filter).getFilterString(); if (field.equals("name")) { q.append(" where lower(s." + field + ") LIKE '" + value + "%'"); } else if (field.equals("id")) { if (checkString(value)) { q.append(" where s." + field + " = '" + value + "'"); } } } } return result; } public boolean checkString(String string) { try { Integer.parseInt(string); } catch (Exception e) { return false; } return true; } public int getProcedureCountByServiceId(Long serviceId, AdvancedFilterableSupport newSender) { StringBuilder q = new StringBuilder("select count(p) from Procedure p where p.service.id=:serviceId "); if (newSender != null) { Set<Timestamp> timestamps = procedureQueryFilters(newSender, q); Iterator<Timestamp> iterator = timestamps.iterator(); if (timestamps.size() == 1) { return em.createQuery(q.toString(), Number.class).setParameter("serviceId", serviceId).setParameter("value", iterator.next()).getSingleResult().intValue(); } else if (timestamps.size() == 2) { Timestamp next = iterator.next(); Timestamp next1 = iterator.next(); return em.createQuery(q.toString(), Number.class).setParameter("serviceId", serviceId).setParameter("startValue", next).setParameter("endValue", next1).getSingleResult().intValue(); } } return em.createQuery(q.toString(), Number.class) .setParameter("serviceId", serviceId).getSingleResult().intValue(); } public int getProcedureCount(ProcedureType type, AdvancedFilterableSupport newSender) { StringBuilder q = new StringBuilder("select count(p) from Procedure p where p.type=:type"); if (newSender != null) { Set<Timestamp> timestamps = procedureQueryFilters(newSender, q); Iterator<Timestamp> iterator = timestamps.iterator(); if (timestamps.size() == 1) { return em.createQuery(q.toString(), Number.class).setParameter("type", type).setParameter("value", iterator.next()).getSingleResult().intValue(); } else if (timestamps.size() == 2) { Timestamp next = iterator.next(); Timestamp next1 = iterator.next(); return em.createQuery(q.toString(), Number.class).setParameter("type", type).setParameter("startValue", next).setParameter("endValue", next1).getSingleResult().intValue(); } } return em.createQuery(q.toString(), Number.class).setParameter("type", type).getSingleResult().intValue(); } public Procedure getProcedure(String id) { return em.createQuery("select p from Procedure p where p.id = :procedureId?", Procedure.class) .setParameter("procedureId", Long.parseLong(id)).getSingleResult(); } public int getApServiceCount(AdvancedFilterableSupport newSender) { StringBuilder q = new StringBuilder("select count(s) from Service s"); if (newSender != null) { Set<Timestamp> timestamps = serviceQueryFilters(newSender, q); Iterator<Timestamp> iterator = timestamps.iterator(); if (timestamps.size() == 1) { return em.createQuery(q.toString(), Number.class).setParameter("value", iterator.next()).getSingleResult().intValue(); } else if (timestamps.size() == 2) { Timestamp next = iterator.next(); Timestamp next1 = iterator.next(); return em.createQuery(q.toString(), Number.class).setParameter("startValue", next).setParameter("endValue", next1).getSingleResult().intValue(); } } return em.createQuery(q.toString(), Number.class).getSingleResult().intValue(); } public Service getApService(String id) { return em.find(Service.class, Long.parseLong(id)); } public List<Service> getApServices(int start, int count, String[] order, boolean[] asc, AdvancedFilterableSupport newSender) { StringBuilder q = new StringBuilder("select s from Service s"); Set<Timestamp> timestamps = null; if (newSender != null) { timestamps = serviceQueryFilters(newSender, q); } for (int i = 0; i < order.length; i++) { if (i == 0) { q.append(" order by "); } else { q.append(", "); } q.append("s.").append(order[i]).append(asc[i] ? " asc" : " desc"); } if (newSender != null) { Iterator<Timestamp> iterator = timestamps.iterator(); if (timestamps.size() == 1) { return em.createQuery(q.toString(), Service.class).setParameter("value", iterator.next()).setFirstResult(start).setMaxResults(count).getResultList(); } else if (timestamps.size() == 2) { Timestamp next = iterator.next(); Timestamp next1 = iterator.next(); return em.createQuery(q.toString(), Service.class).setParameter("startValue", next).setParameter("endValue", next1).setFirstResult(start).setMaxResults(count).getResultList(); } } return em.createQuery(q.toString(), Service.class).setFirstResult(start).setMaxResults(count).getResultList(); } public Service createApService(String name, Long code, String login) { if (hasServiceWithSameRegisterCode(code)) { throw new RuntimeException("Услуга с таким кодом уже существует"); } Service service = new Service(); service.setCreator(em.find(Employee.class, login)); service.setName(name); service.setRegisterCode(code); em.persist(service); return service; } public long createApService(String name, Long code, String login, List<String> declarantTypes) { if (hasServiceWithSameRegisterCode(code)) { return 0; } Service service = new Service(); service.setCreator(em.find(Employee.class, login)); service.setName(name); service.setRegisterCode(code); service.setDeclarantTypes(declarantTypes); em.persist(service); return service.getId(); } public Boolean updateApservice(String id, String name, Long code, List<String> declarantTypes) { Service service = em.find(Service.class, Long.parseLong(id)); if (code != null && !code.equals(service.getRegisterCode()) && hasServiceWithSameRegisterCode(code)) { return true; } service.setRegisterCode(code); service.setName(name); service.setDeclarantTypes(declarantTypes); em.persist(service); return false; } public Service updateApservice(Long id, String name, Long code) { Service service = em.find(Service.class, id); if (code != null && !code.equals(service.getRegisterCode()) && hasServiceWithSameRegisterCode(code)) { throw new RuntimeException("Услуга с таким кодом уже существует"); } service.setRegisterCode(code); service.setName(name); em.persist(service); return service; } public boolean existProcessDefinitionWithKeyOtherProcedure(String procedureId, String key) { int count = em .createQuery( "select count(e) from procedure_process_definition e where e.procedure.id!=:procedureId and e.processDefinitionKey=:processDefinitionKey and e.child is null ", Number.class).setParameter("procedureId", Long.parseLong(procedureId)) .setParameter("processDefinitionKey", key.trim()).getSingleResult().intValue(); return count > 0; } public ProcedureProcessDefinition createProcessDefination(String procedureId, ProcessDefinition processDefinition, String login, String processDefId) { ProcedureProcessDefinition ppd = new ProcedureProcessDefinition(); ProcedureProcessDefinition processDefenition = StringUtils.isEmpty(processDefId) ? null : getProcessDefenition(processDefId); if (StringUtils.isEmpty(processDefId)) { Double newVersion = 0.00; if (getProcessDefenitionCountByProcedureId(procedureId) > 0) { newVersion = em .createQuery( "select max(s.version) from procedure_process_definition s where s.procedure.id=:procedureId", Number.class).setParameter("procedureId", Long.parseLong(procedureId)) .getSingleResult().doubleValue(); } ppd.setVersion(newVersion.intValue() + 1.00); ppd.setStatus(DefinitionStatus.Created); } else { Double version = (processDefenition == null || processDefenition.getVersion() == null) ? 1.00 : processDefenition.getVersion(); ppd.setVersion(version + 0.01); ppd.setStatus(DefinitionStatus.Debugging); } Procedure procedure = getProcedure(procedureId); ppd.setProcedure(procedure); ppd.setCreator(em.find(Employee.class, login)); ppd.setProcessDefinitionId(processDefinition.getId()); ppd.setProcessDefinitionKey(processDefinition.getKey()); em.persist(ppd); if (!StringUtils.isEmpty(processDefId) && processDefenition != null) { processDefenition.setStatus(DefinitionStatus.Archive); processDefenition.setChild(ppd); em.persist(processDefenition); } updateProcedureStatusAndVersion(procedureId); return ppd; } public boolean updateProcessDefinationStatus(String processDefinitionId, DefinitionStatus newStatus) { return updateProcessDefinationStatus(processDefinitionId, newStatus, 0); } public boolean updateProcessDefinationStatus(String processDefinitionId, DefinitionStatus newStatus, int waitOfMinCount) { ProcedureProcessDefinition processDefenition = getProcessDefenition(processDefinitionId); DefinitionStatus status = processDefenition.getStatus(); if (!status.getAvailableStatus().contains(newStatus)) { return false; } if (DefinitionStatus.Work.equals(newStatus)) { for (ProcedureProcessDefinition ppd : getProcessDefenitionWithStatus(processDefenition, DefinitionStatus.Work)) { updateProcessDefinationStatus(ppd.getProcessDefinitionId(), DefinitionStatus.Archive); } } if (DefinitionStatus.Archive.equals(newStatus)) { if (Flash.flash().getProcessEngine().getRuntimeService().createProcessInstanceQuery().processDefinitionId(processDefinitionId).count() > waitOfMinCount) { newStatus = DefinitionStatus.PathToArchive; } } processDefenition.setStatus(newStatus); em.persist(processDefenition); updateProcedureStatusAndVersion(processDefenition.getProcedure().getId()); return true; } public void updateProcedureStatusAndVersion(String procedureId) { Procedure procedure = getProcedure(procedureId); String version = procedure.getVersion(); String status = procedure.getStatus(); for (ProcedureProcessDefinition p : getProcessDefenitionsByProcedureId(procedureId, 0, 1, new String[]{ "status", "version"}, new boolean[]{true, false})) { status = p.getStatus().getLabelName(); version = df.format(p.getVersion()); } procedure.setVersion(version); procedure.setStatus(status); em.persist(procedure); } DecimalFormat df = new DecimalFormat("##.00"); public int getProcessDefenitionCountByProcedureId(String procedureId) { return em .createQuery( "select count(e) from procedure_process_definition e where e.procedure.id=:procedureId and e.child is null", Number.class).setParameter("procedureId", Long.parseLong(procedureId)).getSingleResult() .intValue(); } public List<ProcedureProcessDefinition> getProcessDefenitionsByProcedureId(String procedureId, int start, int count, String[] order, boolean[] asc) { StringBuilder q = new StringBuilder( "select s from procedure_process_definition s where s.procedure.id=:procedureId and s.child is null"); for (int i = 0; i < order.length; i++) { if (i == 0) { q.append(" order by "); } else { q.append(", "); } q.append("s.").append(order[i]).append(asc[i] ? " asc" : " desc"); } return em.createQuery(q.toString(), ProcedureProcessDefinition.class) .setParameter("procedureId", Long.parseLong(procedureId)).setFirstResult(start).setMaxResults(count) .getResultList(); } public ProcedureProcessDefinition getProcessDefenition(String id) { return em.find(ProcedureProcessDefinition.class, id); } public List<ProcedureProcessDefinition> getProcessDefenitionWithStatus(ProcedureProcessDefinition p, DefinitionStatus status) { return em.createQuery( "select s from procedure_process_definition s where s.procedure.id=:procedureId and s.child is null and s.status=:status", ProcedureProcessDefinition.class) .setParameter("procedureId", Long.parseLong(p.getProcedure().getId())) .setParameter("status", status) .getResultList(); } private class ServSearchByIdPredicate implements Predicate<Service> { private Long servId; public ServSearchByIdPredicate(Long servId) { this.servId = servId; } @Override public boolean apply(Service input) { return input != null && input.getId().equals(this.servId); } } public void loadServiceData(InputStream data, final String currentUserName) throws IOException { Preconditions.checkNotNull(data); Preconditions.checkArgument(StringUtils.isNotBlank(currentUserName), "User name is blank"); ServiceFixtureParser parser = new ServiceFixtureParser(); // загрузка справочников final Collection<Service> serviceList = new LinkedList<Service>(); serviceList.addAll((findAllServices())); final Collection<Procedure> procedures = new LinkedList<Procedure>(); procedures.addAll(findAllProcedures()); parser.loadFixtures(data, new ServiceFixtureParser.PersistenceCallback() { @Override public Long onServiceComplete(String srvName, Long regCode) { List<Service> searchedSrv = ImmutableList.copyOf(Collections2.filter(serviceList, new ServiceByRegCodePredicate(regCode))); Long result; if (searchedSrv.size() > 0) { Service service = updateApservice(searchedSrv.get(0).getId(), srvName, regCode); result = service.getId(); } else { Service service = createApService(srvName, regCode, currentUserName); serviceList.add(service); result = service.getId(); } return result; } @Override public void onProcedureComplete(String name, Long regCode, long servId) { List<Service> parentList = ImmutableList.copyOf(Collections2.filter(serviceList, new ServSearchByIdPredicate(servId))); Service parent = parentList.size() > 0 ? parentList.get(0) : null; if (parent != null) { List<Long> children = em.createQuery("select p.id from Procedure p where p.service.id = :service" + " and p.registerCode = :regCode", Long.class) .setParameter("service", servId) .setParameter("regCode", regCode) .getResultList(); if (children.size() > 0) { updateProcedure(children.get(0), name, regCode); } else { List<String> list = em.createQuery("select p.name from Procedure p where p.registerCode = :regCode", String.class) .setParameter("regCode", regCode) .getResultList(); if (list.size() > 0) { throw new RuntimeException("Процедура с кодом " + regCode + " уже существует: " + list.get(0)); } else { Procedure procedure = createProcedure(name, null, Long.toString(servId), regCode, currentUserName, ProcedureType.Administrative); procedures.add(procedure); } } } else { throw new IllegalStateException("Для порцедуры " + name + " не найдена услуга."); } } }); } private class ServiceByRegCodePredicate implements Predicate<Service> { private Long regCode; public ServiceByRegCodePredicate(Long regCode) { this.regCode = regCode; } @Override public boolean apply(Service input) { return input != null && input.getRegisterCode() != null && input.getRegisterCode().equals(this.regCode); } } }