/*
* Copyright 2015 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.
*
* 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.services.task.commands;
import org.drools.core.util.StringUtils;
import org.jbpm.services.task.exception.CannotAddTaskException;
import org.kie.api.runtime.Context;
import org.kie.api.task.model.Attachment;
import org.kie.api.task.model.Comment;
import org.kie.api.task.model.Group;
import org.kie.api.task.model.OrganizationalEntity;
import org.kie.api.task.model.Status;
import org.kie.api.task.model.User;
import org.kie.internal.task.api.TaskContext;
import org.kie.internal.task.api.TaskModelProvider;
import org.kie.internal.task.api.TaskPersistenceContext;
import org.kie.internal.task.api.model.Deadline;
import org.kie.internal.task.api.model.Deadlines;
import org.kie.internal.task.api.model.Escalation;
import org.kie.internal.task.api.model.InternalAttachment;
import org.kie.internal.task.api.model.InternalComment;
import org.kie.internal.task.api.model.InternalOrganizationalEntity;
import org.kie.internal.task.api.model.InternalPeopleAssignments;
import org.kie.internal.task.api.model.InternalTaskData;
import org.kie.internal.task.api.model.Notification;
import org.kie.internal.task.api.model.Reassignment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
@XmlTransient
@XmlRootElement(name="user-group-callback-task-command")
@XmlAccessorType(XmlAccessType.NONE)
public class UserGroupCallbackTaskCommand<T> extends TaskCommand<T> {
private static final long serialVersionUID = 2675686383800457244L;
private static final Logger logger = LoggerFactory.getLogger(UserGroupCallbackTaskCommand.class);
private Map<String, Boolean> userGroupsMap = new HashMap<String, Boolean>();
private static Set<String> restrictedGroups = new HashSet<String>();
public UserGroupCallbackTaskCommand() {
}
static {
try {
InputStream in = UserGroupCallbackTaskCommand.class.getResourceAsStream("/restricted-groups.properties");
if (in != null) {
Properties props = new Properties();
props.load(in);
restrictedGroups.addAll(props.stringPropertyNames());
}
} catch (Exception e) {
logger.warn("Error when loading restricted groups for human task service {}", e.getMessage());
}
}
protected List<String> doUserGroupCallbackOperation(String userId, List<String> groupIds, TaskContext context) {
groupIds = doCallbackGroupsOperation(userId, groupIds, context);
return filterGroups(groupIds);
}
protected boolean doCallbackUserOperation(String userId, TaskContext context) {
if (userId != null && context.getUserGroupCallback().existsUser(userId)) {
addUserFromCallbackOperation(userId, context);
return true;
}
return false;
}
protected User doCallbackAndReturnUserOperation(String userId, TaskContext context) {
if (userId != null && context.getUserGroupCallback().existsUser(userId)) {
return addUserFromCallbackOperation(userId, context);
}
return null;
}
protected boolean doCallbackGroupOperation(String groupId, TaskContext context) {
if (groupId != null && context.getUserGroupCallback().existsGroup(groupId) && !restrictedGroups.contains(groupId)) {
addGroupFromCallbackOperation(groupId, context);
return true;
}
return false;
}
protected User addUserFromCallbackOperation(String userId, TaskContext context) {
User user = context.getPersistenceContext().findUser(userId);
boolean userExists = user != null;
if (!StringUtils.isEmpty(userId) && !userExists) {
user = TaskModelProvider.getFactory().newUser();
((InternalOrganizationalEntity) user).setId(userId);
persistIfNotExists(user, context);
}
return user;
}
protected void persistIfNotExists(final OrganizationalEntity entity, TaskContext context) {
TaskPersistenceContext tpc = context.getPersistenceContext();
OrganizationalEntity orgEntity = tpc.findOrgEntity(entity.getId());
if( orgEntity == null
|| (orgEntity instanceof Group && entity instanceof User)
|| (orgEntity instanceof User && entity instanceof Group) ) {
tpc.persistOrgEntity(entity);
}
}
protected List<String> doCallbackGroupsOperation(String userId, List<String> groupIds, TaskContext context) {
if (userId != null) {
if (groupIds != null && groupIds.size() > 0) {
List<String> userGroups = filterGroups(context.getUserGroupCallback().getGroupsForUser(userId));
for (String groupId : groupIds) {
if (context.getUserGroupCallback().existsGroup(groupId) && userGroups != null && userGroups.contains(groupId)) {
addGroupFromCallbackOperation(groupId, context);
}
}
} else {
if (!(userGroupsMap.containsKey(userId) && userGroupsMap.get(userId).booleanValue())) {
List<String> userGroups = filterGroups(context.getUserGroupCallback().getGroupsForUser(userId));
if (userGroups != null && userGroups.size() > 0) {
for (String group : userGroups) {
addGroupFromCallbackOperation(group, context);
}
userGroupsMap.put(userId, true);
groupIds = userGroups;
}
}
}
} else {
if (groupIds != null) {
for (String groupId : groupIds) {
addGroupFromCallbackOperation(groupId, context);
}
}
}
return groupIds;
}
protected void addGroupFromCallbackOperation(String groupId, TaskContext context) {
Group group = context.getPersistenceContext().findGroup(groupId);
boolean groupExists = group != null;
if (!StringUtils.isEmpty(groupId) && !groupExists) {
group = TaskModelProvider.getFactory().newGroup();
((InternalOrganizationalEntity) group).setId(groupId);
persistIfNotExists(group, context);
}
}
protected void doCallbackOperationForTaskData(InternalTaskData data, TaskContext context) {
if (data.getActualOwner() != null) {
boolean userExists = doCallbackUserOperation(data.getActualOwner().getId(), context);
if (!userExists) {
// remove it from the task to avoid foreign key constraint exception
data.setActualOwner(null);
data.setStatus(Status.Ready);
}
}
if (data.getCreatedBy() != null) {
boolean userExists = doCallbackUserOperation(data.getCreatedBy().getId(), context);
if (!userExists) {
// remove it from the task to avoid foreign key constraint exception
data.setCreatedBy(null);
}
}
}
protected void doCallbackOperationForPotentialOwners(List<OrganizationalEntity> potentialOwners, TaskContext context) {
List<OrganizationalEntity> nonExistingEntities = new ArrayList<OrganizationalEntity>();
for (OrganizationalEntity orgEntity : potentialOwners) {
if (orgEntity instanceof User) {
boolean userExists = doCallbackUserOperation(orgEntity.getId(), context);
if (!userExists) {
nonExistingEntities.add(orgEntity);
}
}
if (orgEntity instanceof Group) {
boolean groupExists = doCallbackGroupOperation(orgEntity.getId(), context);
if (!groupExists) {
nonExistingEntities.add(orgEntity);
}
}
}
if (!nonExistingEntities.isEmpty()) {
potentialOwners.removeAll(nonExistingEntities);
}
}
protected void doCallbackOperationForPeopleAssignments(InternalPeopleAssignments assignments, TaskContext context) {
List<OrganizationalEntity> nonExistingEntities = new ArrayList<OrganizationalEntity>();
if (assignments != null) {
List<? extends OrganizationalEntity> businessAdmins = assignments.getBusinessAdministrators();
if (businessAdmins != null) {
for (OrganizationalEntity admin : businessAdmins) {
if (admin instanceof User) {
boolean userExists = doCallbackUserOperation(admin.getId(), context);
if (!userExists) {
nonExistingEntities.add(admin);
}
}
if (admin instanceof Group) {
boolean groupExists = doCallbackGroupOperation(admin.getId(), context);
if (!groupExists) {
nonExistingEntities.add(admin);
}
}
}
if (!nonExistingEntities.isEmpty()) {
businessAdmins.removeAll(nonExistingEntities);
nonExistingEntities.clear();
}
}
if (businessAdmins == null || businessAdmins.isEmpty()) {
// throw an exception as it should not be allowed to create task without administrator
throw new CannotAddTaskException("There are no known Business Administrators, task cannot be created according to WS-HT specification");
}
List<? extends OrganizationalEntity> potentialOwners = assignments.getPotentialOwners();
if (potentialOwners != null) {
for (OrganizationalEntity powner : potentialOwners) {
if (powner instanceof User) {
boolean userExists = doCallbackUserOperation(powner.getId(), context);
if (!userExists) {
nonExistingEntities.add(powner);
}
}
if (powner instanceof Group) {
boolean groupExists = doCallbackGroupOperation(powner.getId(), context);
if (!groupExists) {
nonExistingEntities.add(powner);
}
}
}
if (!nonExistingEntities.isEmpty()) {
potentialOwners.removeAll(nonExistingEntities);
nonExistingEntities.clear();
}
}
if (assignments.getTaskInitiator() != null && assignments.getTaskInitiator().getId() != null) {
doCallbackUserOperation(assignments.getTaskInitiator().getId(), context);
}
List<? extends OrganizationalEntity> excludedOwners = assignments.getExcludedOwners();
if (excludedOwners != null) {
for (OrganizationalEntity exowner : excludedOwners) {
if (exowner instanceof User) {
boolean userExists = doCallbackUserOperation(exowner.getId(), context);
if (!userExists) {
nonExistingEntities.add(exowner);
}
}
if (exowner instanceof Group) {
boolean groupExists = doCallbackGroupOperation(exowner.getId(), context);
if (!groupExists) {
nonExistingEntities.add(exowner);
}
}
}
if (!nonExistingEntities.isEmpty()) {
excludedOwners.removeAll(nonExistingEntities);
nonExistingEntities.clear();
}
}
List<? extends OrganizationalEntity> recipients = assignments.getRecipients();
if (recipients != null) {
for (OrganizationalEntity recipient : recipients) {
if (recipient instanceof User) {
boolean userExists = doCallbackUserOperation(recipient.getId(), context);
if (!userExists) {
nonExistingEntities.add(recipient);
}
}
if (recipient instanceof Group) {
boolean groupExists = doCallbackGroupOperation(recipient.getId(), context);
if (!groupExists) {
nonExistingEntities.add(recipient);
}
}
}
if (!nonExistingEntities.isEmpty()) {
recipients.removeAll(nonExistingEntities);
nonExistingEntities.clear();
}
}
List<? extends OrganizationalEntity> stakeholders = assignments.getTaskStakeholders();
if (stakeholders != null) {
for (OrganizationalEntity stakeholder : stakeholders) {
if (stakeholder instanceof User) {
boolean userExists = doCallbackUserOperation(stakeholder.getId(), context);
if (!userExists) {
nonExistingEntities.add(stakeholder);
}
}
if (stakeholder instanceof Group) {
boolean groupExists = doCallbackGroupOperation(stakeholder.getId(), context);
if (!groupExists) {
nonExistingEntities.add(stakeholder);
}
}
}
if (!nonExistingEntities.isEmpty()) {
stakeholders.removeAll(nonExistingEntities);
nonExistingEntities.clear();
}
}
}
}
protected void doCallbackOperationForTaskDeadlines(Deadlines deadlines, TaskContext context) {
if(deadlines != null) {
if(deadlines.getStartDeadlines() != null) {
List<? extends Deadline> startDeadlines = deadlines.getStartDeadlines();
for(Deadline startDeadline : startDeadlines) {
List<? extends Escalation> escalations = startDeadline.getEscalations();
if(escalations != null) {
for(Escalation escalation : escalations) {
List<? extends Notification> notifications = escalation.getNotifications();
List<? extends Reassignment> ressignments = escalation.getReassignments();
if(notifications != null) {
for(Notification notification : notifications) {
List<? extends OrganizationalEntity> recipients = notification.getRecipients();
if(recipients != null) {
for(OrganizationalEntity recipient : recipients) {
if(recipient instanceof User) {
doCallbackUserOperation(recipient.getId(), context);
}
if(recipient instanceof Group) {
doCallbackGroupOperation(recipient.getId(), context);
}
}
}
List<? extends OrganizationalEntity> administrators = notification.getBusinessAdministrators();
if(administrators != null) {
for(OrganizationalEntity administrator : administrators) {
if(administrator instanceof User) {
doCallbackUserOperation(administrator.getId(), context);
}
if(administrator instanceof Group) {
doCallbackGroupOperation(administrator.getId(), context);
}
}
}
}
}
if(ressignments != null) {
for(Reassignment reassignment : ressignments) {
List<? extends OrganizationalEntity> potentialOwners = reassignment.getPotentialOwners();
if(potentialOwners != null) {
for(OrganizationalEntity potentialOwner : potentialOwners) {
if(potentialOwner instanceof User) {
doCallbackUserOperation(potentialOwner.getId(), context);
}
if(potentialOwner instanceof Group) {
doCallbackGroupOperation(potentialOwner.getId(), context);
}
}
}
}
}
}
}
}
}
if(deadlines.getEndDeadlines() != null) {
List<? extends Deadline> endDeadlines = deadlines.getEndDeadlines();
for(Deadline endDeadline : endDeadlines) {
List<? extends Escalation> escalations = endDeadline.getEscalations();
if(escalations != null) {
for(Escalation escalation : escalations) {
List<? extends Notification> notifications = escalation.getNotifications();
List<? extends Reassignment> ressignments = escalation.getReassignments();
if(notifications != null) {
for(Notification notification : notifications) {
List<? extends OrganizationalEntity> recipients = notification.getRecipients();
if(recipients != null) {
for(OrganizationalEntity recipient : recipients) {
if(recipient instanceof User) {
doCallbackUserOperation(recipient.getId(), context);
}
if(recipient instanceof Group) {
doCallbackGroupOperation(recipient.getId(), context);
}
}
}
List<? extends OrganizationalEntity> administrators = notification.getBusinessAdministrators();
if(administrators != null) {
for(OrganizationalEntity administrator : administrators) {
if(administrator instanceof User) {
doCallbackUserOperation(administrator.getId(), context);
}
if(administrator instanceof Group) {
doCallbackGroupOperation(administrator.getId(), context);
}
}
}
}
}
if(ressignments != null) {
for(Reassignment reassignment : ressignments) {
List<? extends OrganizationalEntity> potentialOwners = reassignment.getPotentialOwners();
if(potentialOwners != null) {
for(OrganizationalEntity potentialOwner : potentialOwners) {
if(potentialOwner instanceof User) {
doCallbackUserOperation(potentialOwner.getId(), context);
}
if(potentialOwner instanceof Group) {
doCallbackGroupOperation(potentialOwner.getId(), context);
}
}
}
}
}
}
}
}
}
}
}
protected void doCallbackOperationForComment(Comment comment, TaskContext context) {
if (comment != null) {
if (comment.getAddedBy() != null) {
User entity = doCallbackAndReturnUserOperation(comment.getAddedBy().getId(), context);
if (entity != null) {
((InternalComment)comment).setAddedBy(entity);
}
}
}
}
protected void doCallbackOperationForAttachment(Attachment attachment, TaskContext context) {
if (attachment != null) {
if (attachment.getAttachedBy() != null) {
User entity = doCallbackAndReturnUserOperation(attachment.getAttachedBy().getId(), context);
if (entity != null) {
((InternalAttachment)attachment).setAttachedBy(entity);
}
}
}
}
protected List<String> filterGroups(List<String> groups) {
if (groups != null) {
groups.removeAll(restrictedGroups);
} else{
groups = new ArrayList<String>();
}
return groups;
}
protected boolean isBusinessAdmin(String userId, List<OrganizationalEntity> businessAdmins, TaskContext context) {
List<String> usersGroup = context.getUserGroupCallback().getGroupsForUser(userId);
usersGroup.add(userId);
return businessAdmins.stream().anyMatch(oe -> usersGroup.contains(oe.getId()));
}
@Override
public T execute( Context context ) {
throw new UnsupportedOperationException( "org.jbpm.services.task.commands.UserGroupCallbackTaskCommand.execute -> TODO" );
}
}