/* * 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) 2014, MPL CodeInside http://codeinside.ru */ package ru.codeinside.adm; import com.google.common.base.Function; 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.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.gson.Gson; 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.IdentityService; import org.activiti.engine.ProcessEngine; import org.activiti.engine.RuntimeService; import org.activiti.engine.TaskService; import org.activiti.engine.impl.ServiceImpl; import org.activiti.engine.impl.cmd.GetAttachmentCmd; import org.activiti.engine.impl.context.Context; import org.activiti.engine.impl.interceptor.Command; import org.activiti.engine.impl.interceptor.CommandContext; import org.activiti.engine.impl.interceptor.CommandExecutor; import org.activiti.engine.impl.persistence.entity.ExecutionEntity; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.activiti.engine.impl.task.TaskDefinition; import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Attachment; import org.activiti.engine.task.Task; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang.StringUtils; import org.glassfish.osgicdi.OSGiService; import ru.codeinside.adm.database.Bid; import ru.codeinside.adm.database.BidStatus; import ru.codeinside.adm.database.BidWorkers; import ru.codeinside.adm.database.BusinessCalendarDate; import ru.codeinside.adm.database.ClientRequestEntity; import ru.codeinside.adm.database.DefinitionStatus; import ru.codeinside.adm.database.Directory; import ru.codeinside.adm.database.Employee; import ru.codeinside.adm.database.EnclosureEntity; import ru.codeinside.adm.database.ExternalGlue; import ru.codeinside.adm.database.Group; import ru.codeinside.adm.database.InfoSystem; import ru.codeinside.adm.database.InfoSystemService; import ru.codeinside.adm.database.InfoSystem_; import ru.codeinside.adm.database.News; import ru.codeinside.adm.database.Organization; import ru.codeinside.adm.database.Procedure; import ru.codeinside.adm.database.ProcedureProcessDefinition; import ru.codeinside.adm.database.ProcedureType; import ru.codeinside.adm.database.Role; import ru.codeinside.adm.database.ServiceResponseEntity; import ru.codeinside.adm.database.ServiceUnavailable; import ru.codeinside.adm.database.SystemProperty; import ru.codeinside.adm.database.TaskDates; import ru.codeinside.adm.fixtures.Fx; import ru.codeinside.adm.fixtures.FxDefinition; import ru.codeinside.adm.fixtures.FxDirectory; import ru.codeinside.adm.fixtures.FxDirectoryBase; import ru.codeinside.adm.fixtures.FxInfoSystem; import ru.codeinside.adm.fixtures.FxInfoSystemBase; import ru.codeinside.adm.fixtures.FxInfoSystemService; import ru.codeinside.adm.fixtures.FxMarker; import ru.codeinside.adm.fixtures.FxProcedure; import ru.codeinside.adm.fixtures.FxService; import ru.codeinside.adm.parser.BusinessCalendarParser; import ru.codeinside.adm.parser.EmployeeFixtureParser; import ru.codeinside.calendar.BusinessCalendarDueDateCalculator; import ru.codeinside.calendar.CalendarBasedDueDateCalculator; import ru.codeinside.calendar.DueDateCalculator; import ru.codeinside.gses.activiti.Activiti; import ru.codeinside.gses.activiti.Pair; import ru.codeinside.gses.activiti.forms.CustomStartFormHandler; import ru.codeinside.gses.activiti.forms.CustomTaskFormHandler; import ru.codeinside.gses.activiti.forms.api.duration.DurationPreference; import ru.codeinside.gses.activiti.forms.api.duration.LazyCalendar; import ru.codeinside.gses.manager.ManagerService; import ru.codeinside.gses.service.DeclarantService; import ru.codeinside.gses.webui.Flash; import ru.codeinside.gses.webui.gws.ClientRefRegistry; import ru.codeinside.gses.webui.gws.TRef; import ru.codeinside.gws.api.Client; import ru.codeinside.gws.api.Enclosure; import ru.codeinside.gws.api.ServerResponse; import ru.codeinside.gws.api.ServiceDefinitionParser; import ru.codeinside.log.Actor; import ru.codeinside.log.Log; import javax.ejb.DependsOn; import javax.ejb.Lock; import javax.ejb.LockType; import javax.ejb.Singleton; import javax.ejb.TransactionAttribute; import javax.enterprise.inject.Instance; import javax.inject.Inject; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Order; import javax.persistence.criteria.Path; import javax.persistence.criteria.Root; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Timestamp; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.EnumSet; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; import static javax.ejb.TransactionAttributeType.NOT_SUPPORTED; import static javax.ejb.TransactionAttributeType.REQUIRED; import static javax.ejb.TransactionAttributeType.REQUIRES_NEW; @TransactionAttribute @Singleton @Lock(LockType.READ) @DependsOn("BaseBean") public class AdminServiceImpl implements AdminService { final String INSTANCE = System.getProperty("com.sun.aas.instanceName"); final String HOST = System.getProperty("com.sun.aas.hostName"); final Logger logger = Logger.getLogger(getClass().getName()); @Inject @OSGiService(dynamic = true) protected ServiceDefinitionParser serviceDefinitionParser; @PersistenceContext(unitName = "myPU") EntityManager em; @PersistenceContext(unitName = "logPU") EntityManager emLog; @Inject Instance<ProcessEngine> processEngine; @Inject ManagerService mService; @Inject DeclarantService dService; @Inject ClientRefRegistry registry; private AtomicReference TICKET = new AtomicReference(); @TransactionAttribute(REQUIRES_NEW) public Object afterCreate() { final Object ticket = new Object(); if (TICKET.compareAndSet(null, ticket)) { emLog.persist(new Log(null, "instance", INSTANCE != null ? INSTANCE : HOST, "started", null, true)); return ticket; } return null; } @TransactionAttribute(REQUIRES_NEW) public void preDestroy(Object ticket) { if (ticket != null && TICKET.compareAndSet(ticket, null)) { emLog.persist(new Log(null, "instance", INSTANCE != null ? INSTANCE : HOST, "shutdown", null, true)); } } @Override public Organization createOrganization(String name, String login, Organization parent) { final Organization org = new Organization(); org.setName(name); if (login != null) { org.setCreator(findEmployeeByLogin(login)); } if (parent != null) { parent = em.merge(parent); org.setParent(parent); parent.getOrganizations().add(org); } em.persist(org); return org; } @Override public List<Organization> findAllOrganizations() { TypedQuery<Organization> query = em.createNamedQuery("findAllOrganizations", Organization.class); return query.getResultList(); } private List<Long> findAllOrganizationIds() { TypedQuery<Long> query = em.createNamedQuery("findAllOrganizationIds", Long.class); return query.getResultList(); } @Override public List<Organization> findOrganizationIdsByName(String name) { return em.createQuery("select o from Organization o where lower(o.name) like lower(:name)", Organization.class) .setParameter("name", "%" + name + "%") .getResultList(); } @Override public Organization findOrganizationById(Long id) { return em.find(Organization.class, id); } @Override public void updateOrganization(Organization organization) { em.merge(organization); } @Override @TransactionAttribute(REQUIRED) public Employee createEmployee(String login, String password, String fio, String snils, Set<Role> roles, String creator, long orgId, TreeSet<String> groupExecutor, TreeSet<String> groupSupervisorEmp, TreeSet<String> groupSupervisorOrg) { final Organization org = em.getReference(Organization.class, orgId); return createUser(login, password, fio, snils, roles, creator, org, groupExecutor, groupSupervisorEmp, groupSupervisorOrg); } @Override @TransactionAttribute(REQUIRED) public Employee createEmployee(String login, String password, String fio, String snils, Set<Role> roles, String creator, long orgId) { final Organization org = em.getReference(Organization.class, orgId); return createUser(login, password, fio, snils, roles, creator, org); } Employee createUser(String login, String password, String fio, String snils, Set<Role> roles, String creator, final Organization org) { if (snils != null && !snils.isEmpty()) { snils = snils.replaceAll("\\D+", ""); } Employee employee = new Employee(); employee.setLogin(login); employee.setPasswordHash(DigestUtils.sha256Hex(password)); employee.setFio(fio); employee.setSnils(snils); employee.getRoles().addAll(roles); employee.setCreator(creator); employee.setOrganization(org); employee.setLocked(false); org.getEmployees().add(employee); em.persist(employee); final Set<String> groups = new HashSet<String>(); for (Group group : org.getGroups()) { groups.add(group.getName()); } logger.log(Level.FINE, "GROUPS: " + groups); syncUser(employee, Collections.<Group>emptySet(), groups, processEngine.get().getIdentityService()); return employee; } Employee createUser(String login, String password, String fio, String snils, Set<Role> roles, String creator, final Organization org, TreeSet<String> groupExecutor, TreeSet<String> groupSupervisorEmp, TreeSet<String> groupSupervisorOrg) { if (snils != null && !snils.isEmpty()) { snils = snils.replaceAll("\\D+", ""); } Employee employee = new Employee(); employee.setLogin(login); employee.setPasswordHash(DigestUtils.sha256Hex(password)); employee.setSnils(snils); employee.setFio(fio); employee.getRoles().addAll(roles); employee.setCreator(creator); employee.setOrganization(org); employee.setLocked(false); Set<Group> organizationGroups = new HashSet<Group>(); for (Group g : selectGroupsBySocial(false)) { if (groupSupervisorOrg.contains(g.getName())) { organizationGroups.add(g); } } employee.setOrganizationGroups(organizationGroups); Set<Group> employeeGroups = new HashSet<Group>(); for (Group g : selectGroupsBySocial(true)) { if (groupSupervisorEmp.contains(g.getName())) { employeeGroups.add(g); } } employee.setEmployeeGroups(employeeGroups); org.getEmployees().add(employee); em.persist(employee); setUserGroups(employee, groupExecutor); final Set<String> groups = new HashSet<String>(); for (Group group : org.getGroups()) { groups.add(group.getName()); } logger.log(Level.FINE, "GROUPS: " + groups); syncUser(employee, Collections.<Group>emptySet(), groups, processEngine.get().getIdentityService()); return employee; } @Override public Employee findEmployeeByLogin(String login) { return em.find(Employee.class, login); } @Override public Employee findEmployeeBySnils(String snils) { List<Employee> employees = em.createQuery("SELECT u FROM Employee u WHERE u.snils is NOT NULL AND u.snils = :snils", Employee.class) .setParameter("snils", snils) .getResultList(); if (employees.size() == 1) { return employees.get(0); } else if (employees.size() > 1) { throw new IllegalStateException("Значение СНИЛС " + snils + " не уникально"); } else { return null; } } @Override public boolean isUniqueSnils(String login, String snils) { List<Employee> employees = em.createQuery("SELECT u FROM Employee u WHERE u.snils = :snils AND u.login NOT IN (:login)", Employee.class) .setParameter("snils", snils) .setParameter("login", login) .getResultList(); if (employees.size() > 0) { return false; } else { return true; } } @Override public Set<String> getOrgGroupNames(long orgId) { final Organization org = em.getReference(Organization.class, orgId); final Set<String> item = new TreeSet<String>(); for (Group group : org.getGroups()) { item.add(group.getName()); } return item; } @Override public Set<String> getOrgGroupNames() { return selectGroupNamesBySocial(false); } @Override public Set<String> getEmpGroupNames() { return selectGroupNamesBySocial(true); } @Override public Set<String> selectGroupNamesBySocial(boolean social) { return new TreeSet<String>(em.createNamedQuery("groupNamesBySocial", String.class) .setParameter("social", social).getResultList()); } private List<Group> selectGroupsBySocial(boolean social) { TypedQuery<Group> query = em.createNamedQuery("groupsBySocial", Group.class).setParameter("social", social); return query.getResultList(); } @TransactionAttribute(REQUIRED) @Override public void init() { final ProcessEngine engine = processEngine.get(); if (em.createQuery("select count(o.id) from Organization o", Number.class).getSingleResult().intValue() == 0) { try { final long start = System.currentTimeMillis(); logger.log(Level.WARNING, "Запуск наполнения базы"); loadFixtures(getClass().getClassLoader().getResourceAsStream("fixtures.txt")); final long finish = System.currentTimeMillis(); logger.log(Level.WARNING, "Завершено наполнение базы [" + (finish - start) + "мс]"); } catch (IOException e) { throw new RuntimeException(e); } try { final long start = System.currentTimeMillis(); logger.log(Level.WARNING, "Запуск наполнения маршрутами"); loadProcessFixtures(engine, getClass().getClassLoader().getResourceAsStream("process-fixtures.json")); final long finish = System.currentTimeMillis(); logger.log(Level.WARNING, "Завершено наполнение маршрутами [" + (finish - start) + "мс]"); } catch (IOException e) { throw new RuntimeException(e); } try { final long start = System.currentTimeMillis(); logger.log(Level.WARNING, "Запуск наполнения ВИС"); loadInfoSystemFixtures(getClass().getClassLoader().getResourceAsStream("infosystem-fixtures.json")); final long finish = System.currentTimeMillis(); logger.log(Level.WARNING, "Завершено наполнение ВИС [" + (finish - start) + "мс]"); } catch (IOException e) { throw new RuntimeException(e); } try { final long start = System.currentTimeMillis(); logger.log(Level.WARNING, "Запуск наполнения директорий"); loadDirectoryFixtures(getClass().getClassLoader().getResourceAsStream("directory-fixtures.json")); final long finish = System.currentTimeMillis(); logger.log(Level.WARNING, "Завершено наполнение директорий [" + (finish - start) + "мс]"); } catch (IOException e) { throw new RuntimeException(e); } final long start = System.currentTimeMillis(); logger.log(Level.WARNING, "Отключение привязки сертификатов по умолчанию"); em.createNativeQuery("UPDATE systemproperty SET value='false' WHERE key = 'CertificateVerifier.linkCertificate'") .executeUpdate(); final long finish = System.currentTimeMillis(); logger.log(Level.WARNING, "Привязка отключена [" + (finish - start) + "мс]"); } final IdentityService srv = engine.getIdentityService(); final Set<String> domainGroups = ImmutableSet.copyOf(em.createQuery("SELECT g.name FROM Group g", String.class) .getResultList()); for (org.activiti.engine.identity.Group act : srv.createGroupQuery().list()) { final String groupName = act.getId(); if (!domainGroups.contains(groupName)) { logger.log(Level.WARNING, "Синхронизация потерянной группы " + groupName); final Group group = new Group(); group.setName(groupName); group.setTitle(groupName); em.persist(group); } } // мы внутри транзакции, можем получить текущее соедиенение fixAssignmentHistory(em.unwrap(Connection.class)); } /** * Восстановление связи между исполнителем userTask и заявкой. */ private void fixAssignmentHistory(final Connection connection) { try { final DatabaseMetaData metaData = connection.getMetaData(); if ("H2".equals(metaData.getDatabaseProductName())) { return; // увы, SQL не совместим с H2 } final Statement s = connection.createStatement(); final boolean hasFix; { final ResultSet rs = s.executeQuery( "select value_ from act_ge_property where name_ = 'assignFixed'" ); hasFix = rs.next(); rs.close(); } if (!hasFix) { s.execute( "create temp table fix (" + " bid bigint not null," + " assignee varchar(64) not null" + ") on commit drop" ); s.execute("insert into fix select distinct b.id, h.assignee_ from act_hi_taskinst h, bid b" + " where b.processinstanceid = h.proc_inst_id_ and h.assignee_ is not null"); s.execute("delete from fix using bidworkers where bid=bidworkers.bid_id and assignee=bidworkers.employee_login"); s.execute("insert into bidworkers select bid, assignee from fix"); s.execute("insert into act_ge_property values ('assignFixed', '1', 0)"); } s.close(); } catch (SQLException e) { throw new RuntimeException(e); } } @Override public boolean setOrgGroupNames(final long orgId, final Set<String> names) { final Set<String> oldNames = new HashSet<String>(); final Organization org = em.getReference(Organization.class, orgId); final Set<Group> deletions = new HashSet<Group>(); for (final Group group : org.getGroups()) { final String name = group.getName(); oldNames.add(name); if (!names.contains(name)) { deletions.add(group); } } if (!oldNames.equals(names)) { for (final Group group : deletions) { group.getOrganizations().remove(org); org.getGroups().remove(group); } final Set<String> addNames = new HashSet<String>(names); addNames.removeAll(oldNames); for (final String name : addNames) { final Group group = getOrCreateGroupByName(name, false); group.getOrganizations().add(org); org.getGroups().add(group); } final IdentityService act = processEngine.get().getIdentityService(); for (final Employee employee : org.getEmployees()) { final Set<Group> deletions2 = new HashSet<Group>(deletions); deletions2.removeAll(employee.getGroups()); syncUser(employee, deletions2, addNames, act); } } return !oldNames.equals(names); } Group getOrCreateGroupByName(final String name, boolean social) { final List<Group> groups = em.createNamedQuery("groupByName", Group.class).setParameter("name", name) .getResultList(); final Group group; if (groups.isEmpty()) { group = new Group(social); group.setName(name); group.setTitle(name); em.persist(group); } else { group = groups.get(0); } if (social != group.isSocial()) { throw new IllegalStateException("Группа " + name + (social ? " не социальная" : " социальная")); } return group; } @Override public UserItem getUserItem(String login) { final Employee employee = em.find(Employee.class, login); final UserItem userItem = new UserItem(); userItem.setFio(employee.getFio()); userItem.setSnils(employee.getSnils()); userItem.setRoles(employee.getRoles().isEmpty() ? EnumSet.noneOf(Role.class) : EnumSet.copyOf(employee .getRoles())); final Set<String> current = new TreeSet<String>(); for (Group group : employee.getGroups()) { current.add(group.getName()); } userItem.setGroups(current); final Set<String> employeeGroups = new TreeSet<String>(); for (Group group : employee.getEmployeeGroups()) { employeeGroups.add(group.getName()); } userItem.setEmployeeGroups(employeeGroups); final Set<String> organizationGroups = new TreeSet<String>(); for (Group group : employee.getOrganizationGroups()) { organizationGroups.add(group.getName()); } userItem.setOrganizationGroups(organizationGroups); userItem.setAllSocialGroups(selectGroupNamesBySocial(true)); userItem.setLocked(employee.isLocked()); if (employee.getCertificate() != null) { userItem.setX509(employee.getCertificate().getX509()); } return userItem; } @Override public void setUserItem(final String login, final UserItem userItem) { final Employee e = AdminServiceProvider.get().findEmployeeByLogin(login); e.setFio(userItem.getFio()); String snils = userItem.getSnils(); if (snils != null && !snils.isEmpty()) { snils = snils.replaceAll("\\D+", ""); } e.setSnils(snils); e.setLocked(userItem.isLocked()); e.getRoles().clear(); e.getRoles().addAll(userItem.getRoles()); if (userItem.getPassword1() != null) { e.setPasswordHash(DigestUtils.sha256Hex(userItem.getPassword1())); } setUserGroups(e, userItem.getGroups()); setAvailableGroups(e, userItem.getEmployeeGroups(), userItem.getOrganizationGroups()); boolean canAllowCertificate = userItem.getRoles().contains(Role.Declarant) || userItem.getRoles().contains(Role.Executor) || userItem.getRoles().contains(Role.Supervisor) || userItem.getRoles().contains(Role.SuperSupervisor); if (userItem.getX509() == null || !canAllowCertificate) { e.setCertificate(null); // удалиться сам по orphanRemoval = true } em.persist(e); } private void setUserGroups(final Employee e, Set<String> names) { final Set<String> oldNames = new HashSet<String>(); final Set<Group> deletions = new HashSet<Group>(); for (final Group group : e.getGroups()) { final String name = group.getName(); oldNames.add(name); if (!names.contains(name)) { deletions.add(group); } } // хреновое условие! if (!oldNames.equals(names)) { for (final Group group : deletions) { group.getEmployees().remove(e); e.getGroups().remove(group); } final Set<String> addNames = new HashSet<String>(names); addNames.removeAll(oldNames); for (final String name : addNames) { final Group group = getOrCreateGroupByName(name, true); group.getEmployees().add(e); e.getGroups().add(group); } final Set<Group> deletions2 = new HashSet<Group>(deletions); deletions2.removeAll(e.getOrganization().getGroups()); syncUser(e, deletions2, addNames, processEngine.get().getIdentityService()); } } @Override @TransactionAttribute(REQUIRED) public void loadEmployeeData(InputStream data, final String currentUserName) throws IOException { Preconditions.checkNotNull(data); Preconditions.checkArgument(StringUtils.isNotBlank(currentUserName), "User name is blank"); EmployeeFixtureParser parser = new EmployeeFixtureParser(); // загрузка справочников final Collection<Organization> organizationList = new LinkedList<Organization>(); organizationList.addAll((findAllOrganizations())); final Collection<Employee> employees = new LinkedList<Employee>(); employees.addAll(findAllEmployees()); parser.loadFixtures(data, new EmployeeFixtureParser.PersistenceCallback() { @Override public Long onOrganizationComplete(String orgName, Set<String> groups, Long ownerId) { List<Organization> searchedOrg = ImmutableList.copyOf(Collections2.filter(organizationList, new OrgBySearchNamePredicate( orgName) )); Long result; if (searchedOrg.size() > 0) { result = searchedOrg.get(0).getId(); } else { // поиск родительской организации List<Organization> parentList = ImmutableList.copyOf(Collections2.filter(organizationList, new OrgSearchByIdPredicate( ownerId) )); Organization parent = parentList.size() > 0 ? parentList.get(0) : null; Organization organization = createOrganization(orgName, currentUserName, parent); organizationList.add(organization); // назначаем права result = organization.getId(); if (!groups.isEmpty()) { setOrgGroupNames(result, groups); } } return result; } @Override public void onUserComplete(String login, String pwd, String name, String snils, long orgId, Set<Role> roles, Set<String> groups) { Preconditions.checkArgument(StringUtils.isNotBlank(pwd), "У пользователя %s не задан пароль", login); Preconditions.checkArgument(StringUtils.isNotBlank(login), "У пользователя %s не задан login", name); Preconditions.checkArgument(StringUtils.isNotBlank(name), "У пользователя %s не указано имя", login); // получить пользователя по логину List<Employee> filterEmployee = ImmutableList.copyOf(Collections2.filter(employees, new EmployeeByLoginPredicate(login))); if (filterEmployee.size() == 0) {// если пользователя нет, то создать List<Organization> parentList = ImmutableList.copyOf(Collections2.filter(organizationList, new OrgSearchByIdPredicate(orgId))); // поиск родительской организации Organization parent = parentList.size() > 0 ? parentList.get(0) : null; if (parent != null) { Employee user = createEmployee(login, pwd, name, snils, roles, currentUserName, orgId); employees.add(user); if (!groups.isEmpty()) { setUserGroups(user, groups); } } else { throw new IllegalStateException("Для пользователя " + login + " не найдена организация."); } } } }); } @Override public void saveBidAssignment(final ProcessEngine processEngine, final String processInstanceId, String userLogin) { assert processEngine != null; assert processInstanceId != null; assert userLogin != null; final String superProcessInstanceId = getSuperProcessInstanceId(processEngine, processInstanceId); final Bid bid = getBidByProcessInstanceId(superProcessInstanceId); if (bid != null) { bid.setStatus(BidStatus.Execute); em.merge(bid); final Employee employee = em.find(Employee.class, userLogin); em.merge(new BidWorkers(bid, employee)); } } /** * Получить процесс, запустивший данный процесс. */ private String getSuperProcessInstanceId(final ProcessEngine engine, String processInstanceId) { final RuntimeService runtimeService = engine.getRuntimeService(); while (true) { final ProcessInstance superProcess = runtimeService.createProcessInstanceQuery().subProcessInstanceId(processInstanceId).singleResult(); if (superProcess == null) { return processInstanceId; } processInstanceId = superProcess.getProcessInstanceId(); } } // нужно учесть как группы организации так и персональные! void syncUser(final Employee employee, final Set<Group> deletions, final Set<String> inserts, final IdentityService act) { final String login = employee.getLogin(); if (act.createUserQuery().userId(login).count() < 1) { logger.log(Level.FINE, "+user " + login); act.saveUser(act.newUser(login)); } for (final Group group : deletions) { final String groupName = group.getName(); if (act.createGroupQuery().groupId(groupName).groupMember(login).count() > 0) { logger.log(Level.FINE, "-membership " + login + ", " + groupName); act.deleteMembership(login, groupName); } } for (final String groupName : inserts) { final boolean groupCreation = act.createGroupQuery().groupId(groupName).count() <= 0; if (groupCreation) { logger.log(Level.FINE, "+group " + groupName); act.saveGroup(act.newGroup(groupName)); } if (groupCreation || act.createGroupQuery().groupId(groupName).groupMember(login).count() <= 0) { logger.log(Level.FINE, "+membership " + login + ", " + groupName); act.createMembership(login, groupName); } } } void setAvailableGroups(final Employee e, Set<String> namesEmp, Set<String> namesOrg) { final Set<Group> groupsEmp = new HashSet<Group>(); for (final Group group : selectGroupsBySocial(true)) { final String name = group.getName(); if (namesEmp.contains(name)) { groupsEmp.add(group); } } e.setEmployeeGroups(groupsEmp); final Set<Group> groupsOrg = new HashSet<Group>(); for (final Group group : selectGroupsBySocial(false)) { final String name = group.getName(); if (namesOrg.contains(name)) { groupsOrg.add(group); } } e.setOrganizationGroups(groupsOrg); syncUser(e, Collections.<Group>emptySet(), Collections.<String>emptySet(), processEngine.get() .getIdentityService()); } void loadFixtures(InputStream is) throws IOException { EmployeeFixtureParser parser = new EmployeeFixtureParser(); parser.loadFixtures(is, new EmployeeFixtureParser.PersistenceCallback() { @Override public Long onOrganizationComplete(String orgName, Set<String> groups, Long ownerId) { Organization org = new Organization(); org.setName(orgName); if (ownerId != null) { Organization owner = em.getReference(Organization.class, ownerId); org.setParent(owner); owner.getOrganizations().add(org); logger.log(Level.FINE, "Подразделение " + org.getName() + " -> " + owner.getName() + ", " + groups); } else { logger.log(Level.FINE, "Организация " + org.getName() + ", " + groups); } em.persist(org); if (!groups.isEmpty()) { setOrgGroupNames(org.getId(), groups); } return org.getId(); } @Override public void onUserComplete(String login, String pwd, String name, String snils, long orgId, Set<Role> roles, Set<String> groups) { Organization owner = em.getReference(Organization.class, orgId); logger.log(Level.FINE, "Пользователь " + name + "(" + login + "," + roles + ") -> " + owner.getName() + ", " + groups); if (roles.isEmpty()) { roles.add(Role.Executor); } final Employee user = createUser(login, StringUtils.defaultIfEmpty(pwd, "1"), name, snils, roles, null, owner); if (!groups.isEmpty()) { setUserGroups(user, groups); } } }); } @Override public boolean loadProcessFixtures(ProcessEngine engine, InputStream is) throws IOException { final Fx fx = new Gson().fromJson(new InputStreamReader(is, "UTF8"), Fx.class); for (final String name : fx.markers) { try { final Class<?> clazz = Class.forName(name); if (FxMarker.class.isAssignableFrom(clazz)) { if (!((FxMarker) clazz.newInstance()).enabled()) { return false; } } } catch (ClassNotFoundException e) { // skip } catch (InstantiationException e) { // skip } catch (IllegalAccessException e) { // skip } } for (final FxService srv : fx.services) { List<String> declarantTypes = Arrays.asList(srv.declarantTypes); final long serviceId = mService.createApService(srv.name, null, srv.creator, declarantTypes); for (final FxProcedure proc : srv.procs) { final Procedure procedure = mService.createProcedure( proc.name, proc.description, "" + serviceId, proc.code, proc.creator, ProcedureType.Administrative); String lastId = ""; for (final FxDefinition def : proc.defs) { final InputStream ris = getClass().getClassLoader().getResourceAsStream(def.route); final Deployment deployment = engine.getRepositoryService().createDeployment() .addInputStream(def.route, ris).deploy(); final ProcessDefinition processDef = engine.getRepositoryService().createProcessDefinitionQuery() .deploymentId(deployment.getId()).singleResult(); ProcedureProcessDefinition procdef = mService.createProcessDefination(procedure.getId(), processDef, def.creator, lastId); lastId = procdef.getProcessDefinitionId(); if (def.toStatus != null) { for (final DefinitionStatus status : def.toStatus) { if (!mService.updateProcessDefinationStatus(lastId, status)) { throw new IllegalStateException("Невозможно перевести в " + status + " " + def.route + " из " + proc.name); } } } for (int i = 0; i < def.count; i++) { Map<String, Object> properties = ImmutableMap.<String, Object>of("attach1", "1", "attach2", "2"); dService.declare(engine, lastId, properties, null, def.creator); } } } } return true; } public boolean loadInfoSystemFixtures(InputStream is) throws IOException { final FxInfoSystemBase fx = new Gson().fromJson(new InputStreamReader(is, "UTF8"), FxInfoSystemBase.class); for (final FxInfoSystem system : fx.systems) { try { InfoSystem infosys = createInfoSystem(system.code, system.name, null); if (system.source) { toggleSource(system.code, true); } for (FxInfoSystemService service : system.services) { createInfoSystemService(infosys.getCode(), system.source ? system.code : null, service.address, service.revision, service.sname, service.sversion, service.name, service.available, false ); } } catch (Exception e) { logger.log(Level.INFO, "fx infoSystem " + system.code, e); } } return true; } public boolean loadDirectoryFixtures(InputStream is) throws IOException { final FxDirectoryBase fx = new Gson().fromJson(new InputStreamReader(is, "UTF8"), FxDirectoryBase.class); for (final FxDirectory directory : fx.directories) { try { Directory dir = new Directory(directory.name); dir.setValues(directory.values); em.persist(dir); } catch (Exception e) { logger.log(Level.INFO, "fx infoSystem " + directory.name, e); } } return true; } @Override public int getEmployeesCount(long orgId, boolean locked) { return em.createQuery("select count(e) from Employee e where e.organization.id=:orgId and e.locked=:locked", Number.class) .setParameter("orgId", orgId).setParameter("locked", locked).getSingleResult().intValue(); } @Override public List<Group> getControlledOrgGroupsOf(String login, int startIndex, int count, String[] order, boolean[] asc, AdvancedFilterableSupport newSender) { Employee employee = findEmployeeByLogin(login); if (employee.getRoleNames().contains(Role.SuperSupervisor.description)) { return selectGroupsBySocial(startIndex, count, order, asc, newSender, false); } return getControlledGroups(employee, startIndex, count, order, asc, newSender, "organizationGroups"); } private List<Group> selectGroupsBySocial(int startIndex, int count, String[] order, boolean[] asc, AdvancedFilterableSupport newSender, boolean social) { StringBuilder q = new StringBuilder("SELECT g FROM Group g where g.social = :social"); if (newSender != null) { for (Container.Filter f : newSender.getFilters()) { String field = ((SimpleStringFilter) f).getPropertyId().toString(); q.append(" and lower(g.").append(field).append(") LIKE lower(:").append(field).append(")"); } } for (int i = 0; i < order.length; i++) { if (i == 0) { q.append(" order by "); } else { q.append(", "); } q.append("g.").append(order[i]).append(asc[i] ? " asc" : " desc"); } TypedQuery<Group> query = em.createQuery(q.toString(), Group.class) .setParameter("social", social); if (newSender != null) { for (Container.Filter f : newSender.getFilters()) { String field = ((SimpleStringFilter) f).getPropertyId().toString(); String value = ((SimpleStringFilter) f).getFilterString(); query.setParameter(field, "%" + value + "%"); } } return query .setFirstResult(startIndex) .setMaxResults(count) .getResultList(); } private List<Group> getControlledGroups(Employee employee, int startIndex, int count, String[] order, boolean[] asc, AdvancedFilterableSupport newSender, String target) { StringBuilder q = new StringBuilder("select e." + target + " from Employee e where e = :employee"); if (newSender != null) { for (Container.Filter f : newSender.getFilters()) { String field = ((SimpleStringFilter) f).getPropertyId().toString(); q.append(" and lower(e.").append(target).append(".").append(field).append(") LIKE lower(:").append(field).append(")"); } } for (int i = 0; i < order.length; i++) { if (i == 0) { q.append(" order by "); } else { q.append(", "); } q.append("e.").append(target).append(".").append(order[i]).append(asc[i] ? " asc" : " desc"); } TypedQuery<Group> query = em.createQuery(q.toString(), Group.class).setParameter("employee", employee); if (newSender != null) { for (Container.Filter f : newSender.getFilters()) { String field = ((SimpleStringFilter) f).getPropertyId().toString(); String value = ((SimpleStringFilter) f).getFilterString(); query.setParameter(field, "%" + value + "%"); } } return query .setFirstResult(startIndex) .setMaxResults(count) .getResultList(); } @Override public List<Group> getControlledEmpGroupsOf(String login, int startIndex, int count, String[] order, boolean[] asc, AdvancedFilterableSupport newSender) { Employee employee = findEmployeeByLogin(login); if (employee.getRoleNames().contains(Role.SuperSupervisor.description)) { return selectGroupsBySocial(startIndex, count, order, asc, newSender, true); } return getControlledGroups(employee, startIndex, count, order, asc, newSender, "employeeGroups");//employee.getEmployeeGroups(); } @Override public int getControlledOrgGroupsCount(String login, AdvancedFilterableSupport newSender) { Employee employee = findEmployeeByLogin(login); if (employee.getRoleNames().contains(Role.SuperSupervisor.description)) { return selectGroupsBySocialCount(newSender, false); } return getControlledGroupsCount(employee, newSender, "organizationGroups"); } private int selectGroupsBySocialCount(AdvancedFilterableSupport newSender, boolean social) { StringBuilder q = new StringBuilder("SELECT count(g) FROM Group g where g.social = :social"); if (newSender != null) { for (Container.Filter f : newSender.getFilters()) { String field = ((SimpleStringFilter) f).getPropertyId().toString(); q.append(" and lower(g.").append(field).append(") LIKE lower(:").append(field).append(")"); } } TypedQuery<Long> query = em.createQuery(q.toString(), Long.class).setParameter("social", social); if (newSender != null) { for (Container.Filter f : newSender.getFilters()) { String field = ((SimpleStringFilter) f).getPropertyId().toString(); String value = ((SimpleStringFilter) f).getFilterString(); query.setParameter(field, "%" + value + "%"); } } return query .getSingleResult().intValue(); } private int getControlledGroupsCount(Employee employee, AdvancedFilterableSupport newSender, String target) { StringBuilder q = new StringBuilder("select count(e." + target + ") from Employee e where e = :employee"); if (newSender != null) { for (Container.Filter f : newSender.getFilters()) { String field = ((SimpleStringFilter) f).getPropertyId().toString(); q.append(" and lower(e.").append(target).append(".").append(field).append(") LIKE lower(:").append(field).append(")"); } } TypedQuery<Long> query = em.createQuery(q.toString(), Long.class).setParameter("employee", employee); if (newSender != null) { for (Container.Filter f : newSender.getFilters()) { String field = ((SimpleStringFilter) f).getPropertyId().toString(); String value = ((SimpleStringFilter) f).getFilterString(); query.setParameter(field, "%" + value + "%"); } } return query .getSingleResult().intValue(); } @Override public int getControlledEmpGroupsCount(String login, AdvancedFilterableSupport newSender) { Employee employee = findEmployeeByLogin(login); if (employee.getRoleNames().contains(Role.SuperSupervisor.description)) { return selectGroupsBySocialCount(newSender, true); } return getControlledGroupsCount(employee, newSender, "employeeGroups"); } @Override public List<Employee> getOrgGroupMembers(String groupName, String taskId, int startIndex, int count) { Group group = em.createQuery("select g from Group g where g.name=:groupName", Group.class).setParameter("groupName", groupName).getSingleResult(); Set<Organization> organizations = group.getOrganizations(); List<Employee> executors = new ArrayList<Employee>(); ProcessEngine engine = Flash.flash().getProcessEngine(); TaskService taskService = engine.getTaskService(); IdentityService identityService = engine.getIdentityService(); for (Organization organization : organizations) { for (Employee employee : organization.getEmployees()) { if (employee.getRoles().contains(Role.Executor) && canClaim(taskId, employee, taskService, identityService)) { executors.add(employee); } } } return executors.subList(startIndex, startIndex + count); } @Override public List<Employee> getEmpGroupMembers(String groupName, String taskId, int startIndex, int count) { Group group = em.createQuery("select g from Group g where g.name=:groupName", Group.class).setParameter("groupName", groupName).getSingleResult(); List<Employee> allEmployees = new ArrayList<Employee>(group.getEmployees()); List<Employee> executors = new ArrayList<Employee>(); ProcessEngine engine = Flash.flash().getProcessEngine(); TaskService taskService = engine.getTaskService(); IdentityService identityService = engine.getIdentityService(); for (Employee e : allEmployees) { if (e.getRoles().contains(Role.Executor) && canClaim(taskId, e, taskService, identityService)) { executors.add(e); } } return executors.subList(startIndex, startIndex + count); } @Override public int getOrgGroupMembersCount(String groupName, String taskId) { Group group = em.createQuery("select g from Group g where g.name=:groupName", Group.class).setParameter("groupName", groupName).getSingleResult(); Set<Organization> organizations = group.getOrganizations(); int size = 0; ProcessEngine engine = Flash.flash().getProcessEngine(); TaskService taskService = engine.getTaskService(); IdentityService identityService = engine.getIdentityService(); for (Organization organization : organizations) { for (Employee employee : organization.getEmployees()) { if (employee.getRoles().contains(Role.Executor) && canClaim(taskId, employee, taskService, identityService)) { size++; } } } return size; } private boolean canClaim(String taskId, Employee employee, TaskService taskService, IdentityService identityService) { boolean canClaim = taskService.createTaskQuery().taskCandidateUser(employee.getLogin()).taskId(taskId).count() == 1; List<String> candidateGroups = Lists.newArrayList(); for (org.activiti.engine.identity.Group g : identityService.createGroupQuery().groupMember(employee.getLogin()).list()) { candidateGroups.add(g.getId()); } boolean canClaimByGroup = taskService.createTaskQuery().taskCandidateGroupIn(candidateGroups).taskId(taskId).count() == 1; return canClaim || canClaimByGroup; } @Override public int getEmpGroupMembersCount(String groupName, String taskId) { Group group = em.createQuery("select g from Group g where g.name=:groupName", Group.class).setParameter("groupName", groupName).getSingleResult(); int size = 0; ProcessEngine engine = Flash.flash().getProcessEngine(); TaskService taskService = engine.getTaskService(); IdentityService identityService = engine.getIdentityService(); for (Employee e : group.getEmployees()) { if (e.getRoles().contains(Role.Executor) && canClaim(taskId, e, taskService, identityService)) { size++; } } return size; } @Override public long saveClientRequestEntity(ClientRequestEntity entity) { em.persist(entity); return entity.getId(); } @Override public ClientRequestEntity getClientRequestEntity(long id) { return em.find(ClientRequestEntity.class, id); } @Override public <T> T withEmployee(final long orgId, final String login, final Function<Employee, T> callback) { final Employee employee = em .createQuery("select e from Employee e where e.login=:login and e.organization.id=:orgId", Employee.class).setParameter("login", login).setParameter("orgId", orgId).getSingleResult(); return callback.apply(employee); } @Override public <T> T withEmployee(final String login, final Function<Employee, T> callback) { final Employee employee = em.getReference(Employee.class, login); return callback.apply(employee); } @Override public <T> T withEmployees(long orgId, boolean locked, int start, int count, String[] order, boolean[] asc, Function<List<Employee>, T> callback) { StringBuilder q = new StringBuilder("select e from Employee e where e.organization.id=:orgId and e.locked=:locked"); for (int i = 0; i < order.length; i++) { if (i == 0) { q.append(" order by "); } else { q.append(", "); } q.append("e.").append(order[i]).append(asc[i] ? " asc" : " desc"); } List<Employee> employees = em.createQuery(q.toString(), Employee.class) .setParameter("orgId", orgId) .setParameter("locked", locked) .setFirstResult(start) .setMaxResults(count).getResultList(); return callback.apply(employees); } public boolean createGroup(String name, String title, Boolean social) { final List<Group> groups = em.createNamedQuery("groupByName", Group.class).setParameter("name", name) .getResultList(); final Group group; boolean empty = groups.isEmpty(); if (empty) { group = new Group(social); group.setName(name); group.setTitle(title); em.persist(group); } return empty; } @Override public void deleteGroup(Long id) { final Group group = em.find(Group.class, id); if (group != null) { processEngine.get().getIdentityService().deleteGroup(group.getName()); em.remove(group); Set<Employee> socialEmployees = ImmutableSet.copyOf(group.getEmployees()); Set<Employee> organizationEmployees = new HashSet<Employee>(); for (Organization organization : group.getOrganizations()) { for (Employee employee : organization.getEmployees()) { for (Role role : employee.getRoles()) { if (role == Role.Executor) { organizationEmployees.add(employee); } } } } removeUsersFromDeletedGroup(id, socialEmployees); removeUsersFromDeletedGroup(id, organizationEmployees); } } private void removeUsersFromDeletedGroup(Long id, Set<Employee> employees) { for (Employee employee : employees) { Set<String> employeeGroupsAfterDelete = new HashSet<String>(); for (Group group1 : employee.getGroups()) { if (!group1.getId().equals(id)) { employeeGroupsAfterDelete.add(group1.getName()); } } setUserGroups(employee, employeeGroupsAfterDelete); } } public List<Group> findGroupByName(String name) { return em.createNamedQuery("groupByName", Group.class).setParameter("name", name) .getResultList(); } public Boolean findUsesInfoSystemService(String sname, String sversion) { return em.createQuery("select count(s) from InfoSystemService s where s.sname=:sname and s.sversion=:sversion", Number.class) .setParameter("sname", sname).setParameter("sversion", sversion).getSingleResult().intValue() == 0; } public List<Employee> findAllEmployees() { TypedQuery<Employee> query = em.createNamedQuery("findAllEmployees", Employee.class); return query.getResultList(); } private List<String> findAllEmployeeLogins() { TypedQuery<String> query = em.createNamedQuery("findAllEmployeeLogins", String.class); return query.getResultList(); } public void setOrganizationInGroup(Group group, TreeSet<String> twinValue) { List<Long> orgIds = findAllOrganizationIds(); for (Long orgId : orgIds) { Set<String> groups = getOrgGroupNames(orgId); Boolean change; if (twinValue.contains(orgId.toString())) { change = groups.add(group.getName()); } else { change = groups.remove(group.getName()); } if (change) { setOrgGroupNames(orgId, groups); } } } public void setEmloyeeInGroup(Group group, TreeSet<String> twinValue) { List<String> empLogins = findAllEmployeeLogins(); for (String empLogin : empLogins) { final UserItem userItem = AdminServiceProvider.get().getUserItem(empLogin); Set<String> groups = userItem.getGroups(); Boolean change; if (twinValue.contains(empLogin)) { change = groups.add(group.getName()); } else { change = groups.remove(group.getName()); } if (change) { userItem.setGroups(groups); AdminServiceProvider.get().setUserItem(empLogin, userItem); } } } public Bid getBidByTask(String taskId) { List<Bid> resultList = em .createQuery("select e from Bid e join e.currentSteps c where c in (:taskId)", Bid.class) .setParameter("taskId", taskId).getResultList(); if (resultList.isEmpty()) { return null; } return resultList.get(0); } public Bid getBidByProcessInstanceId(String processInstanceId) { List<Bid> resultList = em .createQuery("select e from Bid e where e.processInstanceId = (:processInstanceId)", Bid.class) .setParameter("processInstanceId", processInstanceId).getResultList(); if (resultList.isEmpty()) { return null; } return resultList.get(0); } public Bid getBid(String bidId) { if (StringUtils.isEmpty(bidId)) { return null; } return em.find(Bid.class, Long.parseLong(bidId)); } public TaskDates getTaskDatesByTaskId(String taskId) { List<TaskDates> ids = em .createQuery("select td from TaskDates td where td.id = :id", TaskDates.class) .setParameter("id", taskId).getResultList(); if (ids == null || ids.isEmpty()) { return null; } return ids.get(0); } public List<Organization> getRootOrganizations() { List<Organization> root = new ArrayList<Organization>(); List<Organization> all = findAllOrganizations(); for (Organization org : all) { if (org.getParent() == null) { root.add(org); } } return root; } @Override public int countInfoSystems(boolean source) { final CriteriaBuilder _ = em.getCriteriaBuilder(); final CriteriaQuery<Number> query = _.createQuery(Number.class); final Root<InfoSystem> infoSystems = query.from(InfoSystem.class); if (source) { query.where(_.equal(infoSystems.get(InfoSystem_.source), true)); } return count(query.select(_.count(infoSystems))); } @Override public List<InfoSystem> queryInfoSystems(boolean source, String[] sort, boolean[] asc, int start, int count) { final CriteriaBuilder c = em.getCriteriaBuilder(); final CriteriaQuery<InfoSystem> query = c.createQuery(InfoSystem.class); final Root<InfoSystem> system = query.from(InfoSystem.class); if (source) { query.where(c.equal(system.get(InfoSystem_.source), true)); } query.select(system); if (sort != null) { final Order[] orders = new Order[sort.length]; for (int i = 0; i < sort.length; i++) { final Path<String> path = system.get(sort[i]); orders[i] = asc[i] ? c.asc(path) : c.desc(path); } query.orderBy(orders); } return chunk(start, count, query); } @Override public InfoSystem createInfoSystem(String code, String name, String comment) { InfoSystem system = em.find(InfoSystem.class, code); if (system == null) { system = new InfoSystem(code, name); } else { system.setName(name); } system.setComment(comment); em.persist(system); return system; } @Override public boolean deleteInfoSystem(String code) { InfoSystem system = em.find(InfoSystem.class, code); if (system != null) { Number count = em .createQuery("select count(s) from InfoSystemService s where s.infoSystem=:sys or s.source=:sys", Number.class) .setParameter("sys", system).getSingleResult(); if (count.intValue() == 0) { em.remove(system); singleMain(null); return true; } } return false; } @Override public News createNews(String title, String text) { News news = new News(title, text); em.persist(news); assert news.getId() != null; assert news.getDateCreated() != null; return news; } @Override public void updateNews(Long id, Object title, Object text) { News news = em.find(News.class, id); if (title != null) { news.setTitle((String) title); } if (text != null) { news.setText((String) text); } em.persist(news); } @Override public void deleteNews(Long itemId) { News news = em.find(News.class, itemId); em.remove(news); } @Override public List<News> getNews() { return em.createNamedQuery("allNews", News.class).setMaxResults(3).getResultList(); } @Override public void removeInfoSystemService(long id) { InfoSystemService infoSystemService = em.find(InfoSystemService.class, id); if (infoSystemService != null) { em.remove(infoSystemService); } } @Override public Long createInfoSystemService(String infoSysId, String source, String address, String revision, String sname, String sversion, String name, boolean available, boolean logEnabled) { InfoSystem infoSys = em.find(InfoSystem.class, infoSysId); InfoSystem sourceSys = null; if (source != null) { sourceSys = em.find(InfoSystem.class, source); if (!sourceSys.isSource()) { sourceSys = null; } } InfoSystemService service = new InfoSystemService(); initService(service, address, revision, sname, sversion, name, available, infoSys); service.setLogEnabled(logEnabled); service.setSource(sourceSys); em.persist(service); return service.getId(); } @Override public void updateInfoSystemService(String id, String infoSysId, String source, String address, String revision, String sname, String sversion, String name, boolean available, boolean logEnabled) { InfoSystemService service = em.find(InfoSystemService.class, Long.parseLong(id)); InfoSystem infoSys = em.find(InfoSystem.class, infoSysId); InfoSystem sourceSys = null; if (source != null) { sourceSys = em.find(InfoSystem.class, source); if (!sourceSys.isSource()) { sourceSys = null; } } initService(service, address, revision, sname, sversion, name, available, infoSys); service.setLogEnabled(logEnabled); service.setSource(sourceSys); em.merge(service); } public List<InfoSystemService> getInfoSystemServiceBySName(String name) { return em.createQuery ( "select s from InfoSystemService s where s.sname=:servName and s.available = true", InfoSystemService.class ) .setParameter("servName", name) .getResultList(); } private void initService(InfoSystemService service, String address, String revision, String sname, String sversion, String name, boolean available, InfoSystem infoSys) { service.setInfoSystem(infoSys); service.setAddress(address); service.setRevision(revision); service.setSname(sname); service.setSversion(sversion); service.setName(name); service.setAvailable(available); } private int count(final CriteriaQuery<Number> query) { return em.createQuery(query).getSingleResult().intValue(); } private <T> List<T> chunk(int start, int count, final CriteriaQuery<T> query) { return em.createQuery(query).setFirstResult(start).setMaxResults(count).getResultList(); } @Override public InfoSystem getMainInfoSystem() { List<InfoSystem> list = em.createQuery("select e from InfoSystem e where e.main = true", InfoSystem.class) .setMaxResults(1) .getResultList(); if (list.isEmpty()) { return null; } return list.get(0); } @Override public void createLog(Actor actor, String entityName, String entityId, String action, String info, boolean actionResult) { Log log = new Log(actor, entityName, entityId, action, info, actionResult); emLog.persist(log); } @Override public Actor createActor() { return Flash.getActor(); } @TransactionAttribute(NOT_SUPPORTED) @Override public List<TRef<Client>> getClientRefs() { return registry.getClientRefs(); } @TransactionAttribute(NOT_SUPPORTED) @Override public TRef<Client> getClientRefByNameAndVersion(String name, String version) { return registry.getClientByNameAndVersion(name, version); } @Override public ExternalGlue getGlueByProcessInstanceId(String processInstanceId) { return nullOrFirst(em.createQuery ( "select s from ExternalGlue s where s.processInstanceId=:processInstanceId", ExternalGlue.class ) .setParameter("processInstanceId", processInstanceId) .getResultList() ); } private <T> T nullOrFirst(List<T> resultList) { if (resultList == null || resultList.isEmpty()) { return null; } return resultList.get(0); } @Override @TransactionAttribute(REQUIRED) public void saveServiceResponse(ServiceResponseEntity response, List<Enclosure> enclosures, Map<Enclosure, String[]> enclosureToId) { List<ServiceResponseEntity> resultList = em.createQuery( "select s from ServiceResponseEntity s where s.bid=:bidId and s.status=:status", ServiceResponseEntity.class) .setParameter("bidId", response.getBid()) .setParameter("status", response.status) .getResultList(); for (final ServiceResponseEntity serviceResponseEntity : resultList) { em.remove(serviceResponseEntity); } em.persist(response); if (enclosures != null && !enclosures.isEmpty()) { // сбросить изменения // Context.getCommandContext().getDbSqlSession().flush(); for (Enclosure enclosure : enclosures) { if (enclosure.content == null || StringUtils.isEmpty(enclosure.zipPath)) { logger.info("skip invalid " + enclosure); continue; } if (enclosureToId.containsKey(enclosure)) { String[] idAndVar = enclosureToId.get(enclosure); String id = idAndVar[0]; String var = idAndVar[1]; Attachment attachment = new GetAttachmentCmd(id).execute(Context.getCommandContext()); if (attachment == null) { logger.info("invalid attachment " + id + " for " + enclosure); } else { EnclosureEntity enclosureEntity = new EnclosureEntity( response, id, var, enclosure.fileName, enclosure.code, enclosure.number, enclosure.zipPath); response.getEnclosures().add(enclosureEntity); em.persist(enclosureEntity); logger.info("persist " + enclosureEntity); } } else { logger.info("skip out-of-process " + enclosure); } } } } @Override public ProcedureProcessDefinition getProcedureProcessDefinitionByProcedureCode(long procedureCode) { List<ProcedureProcessDefinition> resultList = em.createQuery("select e from procedure_process_definition e where e.procedure.registerCode =:procedureCode and e.status =:status", ProcedureProcessDefinition.class) .setParameter("procedureCode", procedureCode).setParameter("status", DefinitionStatus.Work).getResultList(); if (resultList == null || resultList.isEmpty()) { return null; } return resultList.get(0); } public Long getProcedureCodeByProcessDefinitionId(String processDefinitionId) { if (processDefinitionId != null && !processDefinitionId.isEmpty()) { ProcedureProcessDefinition procedureProcessDefinition = em.find(ProcedureProcessDefinition.class, processDefinitionId); if (procedureProcessDefinition != null) { return procedureProcessDefinition.getProcedure().getRegisterCode(); } else { return null; } } else { return null; } } @Override public int countOfServerResponseByBidIdAndStatus(long bidId, String status) { return em .createQuery( "select count(e) from ServiceResponseEntity e where e.bid.id =:bidId and e.status=:status", Number.class ) .setParameter("bidId", bidId) .setParameter("status", status) .getSingleResult().intValue(); } @Override public ServiceResponseEntity getServerResponseEntity(long bidId, String status) { final List<ServiceResponseEntity> entities = em.createQuery("select e from ServiceResponseEntity e where e.bid.id =:bidId and e.status=:status", ServiceResponseEntity.class) .setParameter("bidId", bidId) .setParameter("status", status) .getResultList(); return entities != null && entities.size() > 0 ? entities.get(0) : null; } /** * Точка формирования транзакции. */ @TransactionAttribute(REQUIRED) @Override public ServerResponse getServerResponseByBidIdAndStatus(long bid1, long bidId, String status) { final List<ServiceResponseEntity> entities = em.createQuery ( "select e from ServiceResponseEntity e where e.bid.id =:bidId and e.status=:status", ServiceResponseEntity.class ) .setParameter("bidId", bidId) .setParameter("status", status) .getResultList(); if (entities.isEmpty()) { // no response return null; } final ServiceResponseEntity responseEntity = entities.get(0); final String processInstanceId = responseEntity.getBid().getProcessInstanceId(); logger.info("response with " + responseEntity.getEnclosures().size() + " enclosures"); ProcessEngine engine = processEngine.get(); RuntimeService runtimeService = engine.getRuntimeService(); final CommandExecutor commandExecutor = ((ServiceImpl) runtimeService).getCommandExecutor(); final List<Enclosure> attachments = commandExecutor.execute(new Command<List<Enclosure>>() { @Override public List<Enclosure> execute(final CommandContext commandContext) { ExecutionEntity execution = commandContext .getExecutionManager() .findExecutionById(processInstanceId); if (execution == null) { logger.info("no runtime instance " + processInstanceId + ", signatures will be used from history"); } final List<Enclosure> enclosures = new ArrayList<Enclosure>(); for (final EnclosureEntity enclosureEntity : responseEntity.getEnclosures()) { String varName = enclosureEntity.getVar(); logger.info("load attachment " + varName + " with id " + enclosureEntity.getId()); Enclosure enclosure = Activiti.createEnclosureInCommandContext(enclosureEntity.getId(), processInstanceId, varName); if (enclosure == null) { logger.warning("not found attachment with id " + enclosureEntity.getId()); } else { enclosure.number = enclosureEntity.getNumber(); enclosure.code = enclosureEntity.getCode(); enclosure.fileName = enclosureEntity.getFileName(); // возможность задания пути: if (enclosureEntity.getZipPath() != null) { enclosure.zipPath = enclosureEntity.getZipPath(); } enclosures.add(enclosure); } } return enclosures; } }); final ServerResponse serverResponse = responseEntity.getServerResponse(); serverResponse.attachmens = attachments; return serverResponse; } public int countOfBidByEmail(String login, AdvancedFilterableSupport newSender) { StringBuilder q = new StringBuilder("select count(distinct s.bid.id) from BidWorkers s where s.employee.login=:login "); Set<Timestamp> timestamps = null; if (newSender != null) { timestamps = archiveQueryFilters(newSender, q); } TypedQuery<Number> query = em.createQuery(q.toString(), Number.class).setParameter("login", login); if (newSender != null) { for (Container.Filter filter : newSender.getFilters()) { if (filter instanceof SimpleStringFilter) { String field = ((SimpleStringFilter) filter).getPropertyId().toString(); String value = ((SimpleStringFilter) filter).getFilterString(); if (field.equals("procedure.name")) { query.setParameter("name", "%" + value + "%"); } else if (field.equals("id")) { try { query.setParameter(field, Long.parseLong(value)); } catch (Exception e) { // } } } } Iterator<Timestamp> iterator = timestamps.iterator(); if (timestamps.size() == 1) { return query.setParameter("value", iterator.next()).getSingleResult().intValue(); } else if (timestamps.size() == 2) { Timestamp next = iterator.next(); Timestamp next1 = iterator.next(); return query.setParameter("startValue", next).setParameter("endValue", next1).getSingleResult().intValue(); } } return query.getSingleResult().intValue(); } public List<Bid> bidsByLogin(String login, final int start, final int count, String[] order, boolean[] asc, AdvancedFilterableSupport newSender) { StringBuilder q = new StringBuilder("select distinct(s.bid) from BidWorkers s where s.employee.login=:login "); Set<Timestamp> timestamps = null; if (newSender != null) { timestamps = archiveQueryFilters(newSender, q); } for (int i = 0; i < order.length; i++) { if (i == 0) { q.append(" order by "); } else { q.append(", "); } q.append("s.bid.").append(order[i]).append(asc[i] ? " asc" : " desc"); } TypedQuery<Bid> query = em.createQuery(q.toString(), Bid.class).setParameter("login", login); if (newSender != null) { for (Container.Filter filter : newSender.getFilters()) { if (filter instanceof SimpleStringFilter) { String field = ((SimpleStringFilter) filter).getPropertyId().toString(); String value = ((SimpleStringFilter) filter).getFilterString(); if (field.equals("procedure.name")) { query.setParameter("name", "%" + value + "%"); } else if (field.equals("id")) { try { query.setParameter(field, Long.parseLong(value)); } catch (Exception e) { // } } } } Iterator<Timestamp> iterator = timestamps.iterator(); if (timestamps.size() == 1) { return query.setParameter("value", iterator.next()).setFirstResult(start).setMaxResults(count).getResultList(); } else if (timestamps.size() == 2) { Timestamp next = iterator.next(); Timestamp next1 = iterator.next(); return query.setParameter("startValue", next).setParameter("endValue", next1).setFirstResult(start).setMaxResults(count).getResultList(); } } return query.setFirstResult(start) .setMaxResults(count).getResultList(); } @TransactionAttribute(NOT_SUPPORTED) @Override public ServiceDefinitionParser getServiceDefinitionParser() { return serviceDefinitionParser; } @Override public int countServiceUnavailableByInfoSystem(long id) { return em.createQuery("select count(s.id) from ServiceUnavailable s where s.infoSystemService.id=:id", Number.class).setParameter("id", id).getSingleResult().intValue(); } @Override public List<ServiceUnavailable> queryServiceUnavailableByInfoSystem(long id, int start, int count) { return em.createQuery("select s from ServiceUnavailable s where s.infoSystemService.id=:id", ServiceUnavailable.class).setParameter("id", id).setFirstResult(start).setMaxResults(count).getResultList(); } @Override @TransactionAttribute(REQUIRES_NEW) public void saveServiceUnavailable(InfoSystemService curService) { ServiceUnavailable serviceUnavailable = new ServiceUnavailable(curService); em.merge(serviceUnavailable); } @Override @TransactionAttribute(REQUIRES_NEW) public String getSystemProperty(String key) { SystemProperty property = em.find(SystemProperty.class, key); if (property == null) { return null; } return property.getValue(); } @Override @TransactionAttribute(REQUIRES_NEW) public void saveSystemProperty(String key, String value) { SystemProperty property = em.find(SystemProperty.class, key); if (property == null) { property = new SystemProperty(); property.setKey(key); } property.setValue(value); em.persist(property); } @Override public void toggleSource(String code, boolean source) { InfoSystem system = em.find(InfoSystem.class, code); if (system != null) { system.setSource(source); if (!source) { system.setMain(false); List<InfoSystemService> services = em .createQuery("select e from InfoSystemService e where e.source=:sys", InfoSystemService.class) .setParameter("sys", system).getResultList(); for (InfoSystemService service : services) { service.setSource(null); em.persist(service); } } em.persist(system); singleMain(null); } } @Override public void toggleMain(String code, boolean main) { InfoSystem system = em.find(InfoSystem.class, code); if (system != null) { system.setSource(true); em.persist(system); singleMain(system); } } public DueDateCalculator getCalendarBasedDueDateCalculator() { return new CalendarBasedDueDateCalculator(); } public DueDateCalculator getBusinessCalendarBasedDueDateCalculator() { List<BusinessCalendarDate> dates = em.createNamedQuery("all", BusinessCalendarDate.class).getResultList(); Set<Date> holidays = Sets.newHashSet(); Set<Date> workdays = Sets.newHashSet(); for (BusinessCalendarDate date : dates) { if (date.getWorkedDay()) { workdays.add(date.getDate()); } else { holidays.add(date.getDate()); } } return new BusinessCalendarDueDateCalculator(workdays, holidays); } @Override public DueDateCalculator getCalendarBasedDueDateCalculator(boolean business) { if (business) { return getBusinessCalendarBasedDueDateCalculator(); } else { return getCalendarBasedDueDateCalculator(); } } @Override @TransactionAttribute(REQUIRED) public Pair<Integer, Integer> importBusinessCalendar(InputStream inputStream) throws IOException, ParseException { List<BusinessCalendarDate> dates = new BusinessCalendarParser().parseBusinessCalendarDate(inputStream); List<BusinessCalendarDate> updates = new ArrayList<BusinessCalendarDate>(dates.size()); for (BusinessCalendarDate newDate : dates) { BusinessCalendarDate oldDate = em.find(BusinessCalendarDate.class, newDate.getDate()); if (oldDate == null) { em.persist(newDate); updates.add(newDate); } else { if (oldDate.getWorkedDay() != newDate.getWorkedDay()) { oldDate.setWorkedDay(newDate.getWorkedDay()); em.persist(oldDate); updates.add(oldDate); } } } em.flush(); Date minDate = null; for (BusinessCalendarDate calendar : updates) { Date date = calendar.getDate(); if (minDate == null || minDate.after(date)) { minDate = date; } } if (minDate != null) { return updateTimeBorders(minDate); } return Pair.of(0, 0); } @Override @TransactionAttribute(REQUIRED) public Pair<Integer, Integer> deleteDateFromBusinessCalendar(Date dateForRemove) { final BusinessCalendarDate businessCalendarDate = em.find(BusinessCalendarDate.class, dateForRemove); if (businessCalendarDate != null) { em.remove(businessCalendarDate); em.flush(); return updateTimeBorders(businessCalendarDate.getDate()); } else { return Pair.of(0, 0); } } private Pair<Integer, Integer> updateTimeBorders(final Date minDate) { final ProcessEngine engine = processEngine.get(); return ((ServiceImpl) engine.getFormService()).getCommandExecutor().execute(new Command<Pair<Integer, Integer>>() { @Override public Pair<Integer, Integer> execute(CommandContext commandContext) { int bidCount = 0; int taskCount = 0; DurationPreference emptyPreference = new DurationPreference(); LazyCalendar lazyCalendar = new LazyCalendar(); List<Bid> bids = em.createQuery( " select b from Bid b join fetch b.procedureProcessDefinition " + " where b.dateFinished is null and b.dateCreated <= :dt " + " order by b.procedureProcessDefinition.processDefinitionId", Bid.class) .setParameter("dt", minDate) .getResultList(); for (Bid bid : bids) { String processDefinitionId = bid.getProcedureProcessDefinition().getProcessDefinitionId(); ProcessDefinitionEntity processDefinition = Context.getProcessEngineConfiguration().getDeploymentCache() .findDeployedProcessDefinitionById(processDefinitionId); if (processDefinition == null) { logger.warning("not found definition for bid(" + bid.getId() + ")"); continue; } DurationPreference bidPreference = ((CustomStartFormHandler) processDefinition.getStartFormHandler()) .getPropertyTree() .getDurationPreference(); if (bidPreference.updateProcessDates(bid, lazyCalendar)) { em.persist(bid); bidCount++; } List<Task> taskList = engine.getTaskService().createTaskQuery().processDefinitionId(processDefinitionId).list(); for (Task task : taskList) { TaskDates taskDates = em.find(TaskDates.class, task.getId()); if (taskDates == null) { logger.warning("not found dates for task(" + task.getId() + ")"); continue; } DurationPreference taskPreference; { TaskDefinition taskDefinition = processDefinition.getTaskDefinitions().get(task.getTaskDefinitionKey()); if (taskDefinition == null) { logger.warning("not found definition for task(" + task.getId() + ")"); taskPreference = emptyPreference; } else { taskPreference = ((CustomTaskFormHandler) taskDefinition.getTaskFormHandler()) .getPropertyTree() .getDurationPreference(); } } if (taskPreference.updateTaskDates(taskDates, lazyCalendar)) { em.persist(taskDates); taskCount++; } } } if (bidCount > 0 || taskCount > 0) { em.flush(); } return Pair.of(bidCount, taskCount); } }); } void singleMain(InfoSystem newChecked) { InfoSystem source = null; InfoSystem checked = null; List<InfoSystem> systems = em.createQuery("select s from InfoSystem s", InfoSystem.class).getResultList(); for (InfoSystem system : systems) { if (system.isSource()) { if (source == null) { source = system; } if (system.isMain()) { checked = system; } } system.setMain(false); em.persist(system); } if (source != null) { if (newChecked != null) { checked = newChecked; } else if (checked == null) { checked = source; } checked.setMain(true); em.persist(checked); } } private Set<Timestamp> archiveQueryFilters(AdvancedFilterableSupport newSender, StringBuilder q) { Set<Timestamp> result = new HashSet<Timestamp>(); 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 s.bid.").append(field).append(" >= :startValue and s.bid.").append(field).append(" <= :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 s.bid.").append(field).append(" >= :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 s.bid.").append(field).append(" <= :value"); } else { String field = ((SimpleStringFilter) filter).getPropertyId().toString(); String value = ((SimpleStringFilter) filter).getFilterString(); if (field.equals("procedure.name")) { q.append(" and (lower(s.bid.procedure.name) LIKE lower(:").append("name") .append(") or lower(s.bid.tag) LIKE lower(:").append("name").append("))"); } else if (field.equals("id")) { try { Long.parseLong(value); q.append(" and s.bid.id = :").append(field); } catch (Exception e) { // } } } } return result; } private class OrgBySearchNamePredicate implements Predicate<Organization> { private String orgName; public OrgBySearchNamePredicate(String orgName) { this.orgName = orgName; } @Override public boolean apply(Organization input) { return input != null && input.getName().equals(this.orgName); } } private class OrgSearchByIdPredicate implements Predicate<Organization> { private Long orgId; public OrgSearchByIdPredicate(Long orgId) { this.orgId = orgId; } @Override public boolean apply(Organization input) { return input != null && input.getId().equals(this.orgId); } } private class EmployeeByLoginPredicate implements Predicate<Employee> { private String login; public EmployeeByLoginPredicate(String login) { this.login = login; } @Override public boolean apply(Employee input) { return input != null && input.getLogin().equals(login); } } }