/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jbpm.kie.services.impl.admin; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jbpm.kie.services.impl.admin.commands.AddPeopleAssignmentsCommand; import org.jbpm.kie.services.impl.admin.commands.AddTaskInputsCommand; import org.jbpm.kie.services.impl.admin.commands.CancelTaskDeadlineCommand; import org.jbpm.kie.services.impl.admin.commands.ListTaskNotificationsCommand; import org.jbpm.kie.services.impl.admin.commands.ListTaskReassignmentsCommand; import org.jbpm.kie.services.impl.admin.commands.RemovePeopleAssignmentsCommand; import org.jbpm.kie.services.impl.admin.commands.RemoveTaskDataCommand; import org.jbpm.kie.services.impl.admin.commands.ScheduleTaskDeadlineCommand; import org.jbpm.runtime.manager.impl.AbstractRuntimeManager; import org.jbpm.services.api.RuntimeDataService; import org.jbpm.services.api.TaskNotFoundException; import org.jbpm.services.api.UserTaskService; import org.jbpm.services.api.admin.ExecutionErrorNotFoundException; import org.jbpm.services.api.admin.TaskNotification; import org.jbpm.services.api.admin.TaskReassignment; import org.jbpm.services.api.admin.UserTaskAdminService; import org.jbpm.services.api.model.UserTaskInstanceDesc; import org.jbpm.shared.services.impl.QueryManager; import org.jbpm.shared.services.impl.TransactionalCommandService; import org.jbpm.shared.services.impl.commands.QueryNameCommand; import org.kie.api.runtime.manager.RuntimeManager; import org.kie.api.runtime.query.QueryContext; import org.kie.api.task.model.I18NText; import org.kie.api.task.model.OrganizationalEntity; import org.kie.internal.identity.IdentityProvider; import org.kie.internal.runtime.error.ExecutionError; import org.kie.internal.runtime.manager.RuntimeManagerRegistry; import org.kie.internal.runtime.manager.context.ProcessInstanceIdContext; import org.kie.internal.task.api.TaskDeadlinesService.DeadlineType; import org.kie.internal.task.api.TaskModelProvider; import org.kie.internal.task.api.model.Deadline; import org.kie.internal.task.api.model.EmailNotification; import org.kie.internal.task.api.model.EmailNotificationHeader; import org.kie.internal.task.api.model.Escalation; import org.kie.internal.task.api.model.InternalI18NText; import org.kie.internal.task.api.model.Language; import org.kie.internal.task.api.model.Notification; import org.kie.internal.task.api.model.Reassignment; public class UserTaskAdminServiceImpl implements UserTaskAdminService { public static final int POT_OWNER = 0; public static final int EXCL_OWNER = 1; public static final int ADMIN = 2; private UserTaskService userTaskService; private RuntimeDataService runtimeDataService; private IdentityProvider identityProvider; private TransactionalCommandService commandService; public void setUserTaskService(UserTaskService userTaskService) { this.userTaskService = userTaskService; } public void setRuntimeDataService(RuntimeDataService runtimeDataService) { this.runtimeDataService = runtimeDataService; } public void setIdentityProvider(IdentityProvider identityProvider) { this.identityProvider = identityProvider; } public void setCommandService(TransactionalCommandService commandService) { this.commandService = commandService; } @Override public void addPotentialOwners(long taskId, boolean removeExisting, OrganizationalEntity... orgEntities) throws TaskNotFoundException { addPeopleAssignment(taskId, removeExisting, POT_OWNER, orgEntities); } @Override public void addExcludedOwners(long taskId, boolean removeExisting, OrganizationalEntity... orgEntities) throws TaskNotFoundException { addPeopleAssignment(taskId, removeExisting, EXCL_OWNER, orgEntities); } @Override public void addBusinessAdmins(long taskId, boolean removeExisting, OrganizationalEntity... orgEntities) throws TaskNotFoundException { addPeopleAssignment(taskId, removeExisting, ADMIN, orgEntities); } @Override public void removePotentialOwners(long taskId, OrganizationalEntity... orgEntities) throws TaskNotFoundException { removePeopleAssignment(taskId, POT_OWNER, orgEntities); } @Override public void removeExcludedOwners(long taskId, OrganizationalEntity... orgEntities) throws TaskNotFoundException { removePeopleAssignment(taskId, EXCL_OWNER, orgEntities); } @Override public void removeBusinessAdmins(long taskId, OrganizationalEntity... orgEntities) throws TaskNotFoundException, IllegalStateException { removePeopleAssignment(taskId, ADMIN, orgEntities); } @Override public void addTaskInput(long taskId, String name, Object value) throws TaskNotFoundException { Map<String, Object> data = new HashMap<>(); data.put(name, value); addTaskInputs(taskId, data); } @Override public void addTaskInputs(long taskId, Map<String, Object> data) throws TaskNotFoundException { UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId); if (task == null) { throw new TaskNotFoundException("Task with id " + taskId + " not found"); } userTaskService.execute(task.getDeploymentId(), ProcessInstanceIdContext.get(task.getProcessInstanceId()), new AddTaskInputsCommand(identityProvider.getName(), taskId, data)); } @Override public void removeTaskInputs(long taskId, String... name) throws TaskNotFoundException { UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId); if (task == null) { throw new TaskNotFoundException("Task with id " + taskId + " not found"); } userTaskService.execute(task.getDeploymentId(), ProcessInstanceIdContext.get(task.getProcessInstanceId()), new RemoveTaskDataCommand(identityProvider.getName(), taskId, Arrays.asList(name), true)); } @Override public void removeTaskOutputs(long taskId, String... name) throws TaskNotFoundException { UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId); if (task == null) { throw new TaskNotFoundException("Task with id " + taskId + " not found"); } userTaskService.execute(task.getDeploymentId(), ProcessInstanceIdContext.get(task.getProcessInstanceId()), new RemoveTaskDataCommand(identityProvider.getName(), taskId, Arrays.asList(name), false)); } @Override public Long reassignWhenNotStarted(long taskId, String timeExpression, OrganizationalEntity... orgEntities) throws TaskNotFoundException { return reassign(taskId, timeExpression, DeadlineType.START, orgEntities); } @Override public Long reassignWhenNotCompleted(long taskId, String timeExpression, OrganizationalEntity... orgEntities) throws TaskNotFoundException { return reassign(taskId, timeExpression, DeadlineType.END, orgEntities); } @Override public Long notifyWhenNotStarted(long taskId, String timeExpression, Notification notification) throws TaskNotFoundException { return notify(taskId, timeExpression, DeadlineType.START, notification); } @Override public Long notifyWhenNotCompleted(long taskId, String timeExpression, Notification notification) throws TaskNotFoundException { return notify(taskId, timeExpression, DeadlineType.END, notification); } @Override public Collection<TaskReassignment> getTaskReassignments(long taskId, boolean activeOnly) throws TaskNotFoundException { UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId); if (task == null) { throw new TaskNotFoundException("Task with id " + taskId + " not found"); } return userTaskService.execute(task.getDeploymentId(), ProcessInstanceIdContext.get(task.getProcessInstanceId()), new ListTaskReassignmentsCommand(identityProvider.getName(), taskId, activeOnly)); } @Override public Collection<TaskNotification> getTaskNotifications(long taskId, boolean activeOnly) throws TaskNotFoundException { UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId); if (task == null) { throw new TaskNotFoundException("Task with id " + taskId + " not found"); } return userTaskService.execute(task.getDeploymentId(), ProcessInstanceIdContext.get(task.getProcessInstanceId()), new ListTaskNotificationsCommand(identityProvider.getName(), taskId, activeOnly)); } @Override public void cancelNotification(long taskId, long notificationId) throws TaskNotFoundException { UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId); if (task == null) { throw new TaskNotFoundException("Task with id " + taskId + " not found"); } userTaskService.execute(task.getDeploymentId(), ProcessInstanceIdContext.get(task.getProcessInstanceId()), new CancelTaskDeadlineCommand(identityProvider.getName(), taskId, notificationId)); } @Override public void cancelReassignment(long taskId, long reassignmentId) throws TaskNotFoundException { UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId); if (task == null) { throw new TaskNotFoundException("Task with id " + taskId + " not found"); } userTaskService.execute(task.getDeploymentId(), ProcessInstanceIdContext.get(task.getProcessInstanceId()), new CancelTaskDeadlineCommand(identityProvider.getName(), taskId, reassignmentId)); } @Override public EmailNotification buildEmailNotification(String subjectStr, List<OrganizationalEntity> recipients, String bodyStr, String fromStr, String replyToStr) { EmailNotification emailNotification = TaskModelProvider.getFactory().newEmialNotification(); Map<Language, EmailNotificationHeader> emailHeaders = new HashMap<Language, EmailNotificationHeader>(); List<I18NText> subjects = new ArrayList<I18NText>(); List<I18NText> names = new ArrayList<I18NText>(); String locale = "en-UK"; EmailNotificationHeader emailHeader = TaskModelProvider.getFactory().newEmailNotificationHeader(); emailHeader.setBody(bodyStr); emailHeader.setFrom(fromStr); emailHeader.setReplyTo(replyToStr); emailHeader.setLanguage(locale); emailHeader.setSubject(subjectStr); Language lang = TaskModelProvider.getFactory().newLanguage(); lang.setMapkey(locale); emailHeaders.put(lang, emailHeader); I18NText subject = TaskModelProvider.getFactory().newI18NText(); ((InternalI18NText) subject).setLanguage(locale); ((InternalI18NText) subject).setText(emailHeader.getSubject());; subjects.add(subject); names.add(subject); emailNotification.setEmailHeaders(emailHeaders); emailNotification.setNames(names); emailNotification.setRecipients(new ArrayList<>(recipients)); emailNotification.setSubjects(subjects); return emailNotification; } /* * Error handling related */ @Override public List<ExecutionError> getErrors(boolean includeAcknowledged, QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); params.put("ack", getAckMode(includeAcknowledged)); applyQueryContext(params, queryContext); List<ExecutionError> execErrors = commandService.execute(new QueryNameCommand<List<ExecutionError>>("getTaskErrors",params)); return execErrors; } @Override public List<ExecutionError> getErrorsByTaskId(long taskId, boolean includeAcknowledged, QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); params.put("taskId", taskId); params.put("ack", getAckMode(includeAcknowledged)); applyQueryContext(params, queryContext); List<ExecutionError> execErrors = commandService.execute(new QueryNameCommand<List<ExecutionError>>("getErrorsByTaskId",params)); return execErrors; } @Override public List<ExecutionError> getErrorsByTaskName(String taskName, boolean includeAcknowledged, QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); params.put("taskName", taskName); params.put("ack", getAckMode(includeAcknowledged)); applyQueryContext(params, queryContext); List<ExecutionError> execErrors = commandService.execute(new QueryNameCommand<List<ExecutionError>>("getErrorsByTaskName",params)); return execErrors; } @Override public List<ExecutionError> getErrorsByTaskName(String processId, String taskName, boolean includeAcknowledged, QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); params.put("processId", processId); params.put("taskName", taskName); params.put("ack", getAckMode(includeAcknowledged)); applyQueryContext(params, queryContext); List<ExecutionError> execErrors = commandService.execute(new QueryNameCommand<List<ExecutionError>>("getErrorsByTaskNameProcessId",params)); return execErrors; } @Override public List<ExecutionError> getErrorsByTaskName(String deploymentId, String processId, String taskName, boolean includeAcknowledged, QueryContext queryContext) { Map<String, Object> params = new HashMap<String, Object>(); params.put("deploymentId", deploymentId); params.put("processId", processId); params.put("taskName", taskName); params.put("ack", getAckMode(includeAcknowledged)); applyQueryContext(params, queryContext); List<ExecutionError> execErrors = commandService.execute(new QueryNameCommand<List<ExecutionError>>("getErrorsByTaskNameProcessIdDeploymentId",params)); return execErrors; } @Override public void acknowledgeError(String... errorId) throws ExecutionErrorNotFoundException { for (String error : errorId) { Map<String, Object> params = new HashMap<String, Object>(); params.put("errorId", error); params.put("ack", false); List<ExecutionError> execErrors = commandService.execute(new QueryNameCommand<List<ExecutionError>>("getErrorById",params)); if (execErrors.isEmpty()) { throw new ExecutionErrorNotFoundException("No execution error found for id " + errorId); } ExecutionError errorInstance = execErrors.get(0); RuntimeManager runtimeManager = RuntimeManagerRegistry.get().getManager(errorInstance.getDeploymentId()); if (runtimeManager != null) { ((AbstractRuntimeManager) runtimeManager).getExecutionErrorManager().getStorage().acknowledge(identityProvider.getName(), errorInstance.getErrorId()); } } } @Override public ExecutionError getError(String errorId) throws ExecutionErrorNotFoundException { Map<String, Object> params = new HashMap<String, Object>(); params.put("errorId", errorId); List<ExecutionError> execErrors = commandService.execute(new QueryNameCommand<List<ExecutionError>>("getErrorByIdSkipAckCheck",params)); if (execErrors.isEmpty()) { throw new ExecutionErrorNotFoundException("No execution error found for id " + errorId); } ExecutionError error = execErrors.get(0); return error; } /* * Internal methods */ protected void addPeopleAssignment(long taskId, boolean removeExisting, int type, OrganizationalEntity... orgEntities) throws TaskNotFoundException { UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId); if (task == null) { throw new TaskNotFoundException("Task with id " + taskId + " not found"); } userTaskService.execute(task.getDeploymentId(), ProcessInstanceIdContext.get(task.getProcessInstanceId()), new AddPeopleAssignmentsCommand(identityProvider.getName(), taskId, type, orgEntities, removeExisting)); } protected void removePeopleAssignment(long taskId, int type, OrganizationalEntity... orgEntities) throws TaskNotFoundException { UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId); if (task == null) { throw new TaskNotFoundException("Task with id " + taskId + " not found"); } userTaskService.execute(task.getDeploymentId(), ProcessInstanceIdContext.get(task.getProcessInstanceId()), new RemovePeopleAssignmentsCommand(identityProvider.getName(), taskId, type, orgEntities)); } protected Long reassign(long taskId, String timeExpression, DeadlineType type, OrganizationalEntity... orgEntities) throws TaskNotFoundException { UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId); if (task == null) { throw new TaskNotFoundException("Task with id " + taskId + " not found"); } List<Escalation> escalations = new ArrayList<Escalation>(); Deadline taskDeadline = TaskModelProvider.getFactory().newDeadline(); taskDeadline.setEscalations(escalations); Escalation escalation = TaskModelProvider.getFactory().newEscalation(); escalations.add(escalation); escalation.setName("Admin reassignment for task " + taskId); List<Reassignment> reassignments = new ArrayList<Reassignment>(); Reassignment reassignment = TaskModelProvider.getFactory().newReassignment(); reassignment.setPotentialOwners(new ArrayList<>(Arrays.asList(orgEntities))); reassignments.add(reassignment); escalation.setReassignments(reassignments); return userTaskService.execute(task.getDeploymentId(), ProcessInstanceIdContext.get(task.getProcessInstanceId()), new ScheduleTaskDeadlineCommand(identityProvider.getName(), taskId, type, taskDeadline, timeExpression)); } protected Long notify(long taskId, String timeExpression, DeadlineType type, Notification notification) throws TaskNotFoundException { UserTaskInstanceDesc task = runtimeDataService.getTaskById(taskId); if (task == null) { throw new TaskNotFoundException("Task with id " + taskId + " not found"); } List<Escalation> escalations = new ArrayList<Escalation>(); Deadline taskDeadline = TaskModelProvider.getFactory().newDeadline(); taskDeadline.setEscalations(escalations); Escalation escalation = TaskModelProvider.getFactory().newEscalation(); escalations.add(escalation); escalation.setName("Admin notification for task " + taskId); List<Notification> notifications = new ArrayList<Notification>(); notifications.add(notification); escalation.setNotifications(notifications); return userTaskService.execute(task.getDeploymentId(), ProcessInstanceIdContext.get(task.getProcessInstanceId()), new ScheduleTaskDeadlineCommand(identityProvider.getName(), taskId, type, taskDeadline, timeExpression)); } protected void applyQueryContext(Map<String, Object> params, QueryContext queryContext) { if (queryContext != null) { params.put("firstResult", queryContext.getOffset()); params.put("maxResults", queryContext.getCount()); if (queryContext.getOrderBy() != null && !queryContext.getOrderBy().isEmpty()) { params.put(QueryManager.ORDER_BY_KEY, queryContext.getOrderBy()); if (queryContext.isAscending()) { params.put(QueryManager.ASCENDING_KEY, "true"); } else { params.put(QueryManager.DESCENDING_KEY, "true"); } } } } protected List<Boolean> getAckMode(boolean includeAcknowledged) { List<Boolean> ackMode = new ArrayList<>(); ackMode.add(false); if (includeAcknowledged) { ackMode.add(true); } return ackMode; } }