/*
* Copyright (c) 2011, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* 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.wso2.carbon.humantask.core.engine.commands;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.CarbonContext;
import org.wso2.carbon.humantask.core.api.event.TaskEventInfo;
import org.wso2.carbon.humantask.core.dao.EventDAO;
import org.wso2.carbon.humantask.core.dao.GenericHumanRoleDAO;
import org.wso2.carbon.humantask.core.dao.OrganizationalEntityDAO;
import org.wso2.carbon.humantask.core.dao.TaskDAO;
import org.wso2.carbon.humantask.core.dao.TaskEventType;
import org.wso2.carbon.humantask.core.dao.TaskStatus;
import org.wso2.carbon.humantask.core.dao.TaskType;
import org.wso2.carbon.humantask.core.engine.HumanTaskCommand;
import org.wso2.carbon.humantask.core.engine.HumanTaskEngine;
import org.wso2.carbon.humantask.core.engine.runtime.api.HumanTaskIllegalAccessException;
import org.wso2.carbon.humantask.core.engine.runtime.api.HumanTaskIllegalArgumentException;
import org.wso2.carbon.humantask.core.engine.runtime.api.HumanTaskIllegalOperationException;
import org.wso2.carbon.humantask.core.engine.runtime.api.HumanTaskIllegalStateException;
import org.wso2.carbon.humantask.core.engine.runtime.api.HumanTaskRuntimeException;
import org.wso2.carbon.humantask.core.engine.util.CommonTaskUtil;
import org.wso2.carbon.humantask.core.engine.util.OperationAuthorizationUtil;
import org.wso2.carbon.humantask.core.internal.HumanTaskServiceComponent;
import java.util.List;
/**
* Abstract class for HumanTaskCommand. Contains the common operations and properties
*/
public abstract class AbstractHumanTaskCommand implements HumanTaskCommand {
private static final Log log = LogFactory.getLog(Claim.class);
/**
* The human task engine
*/
private HumanTaskEngine engine;
/**
* The task related to this operation
*/
private TaskDAO task;
/**
* The caller of the operation.
*/
private OrganizationalEntityDAO operationInvoker;
/**
* The task event related to this command.
*/
private EventDAO event;
protected HumanTaskEngine getEngine() {
return engine;
}
protected TaskDAO getTask() {
return task;
}
protected OrganizationalEntityDAO getOperationInvoker() {
return operationInvoker;
}
protected EventDAO getEvent() {
return event;
}
/**
* @param invokerUserName : The user name of the operation invoker.
* @param taskId : The task id.
*/
public AbstractHumanTaskCommand(String invokerUserName, Long taskId) {
engine = HumanTaskServiceComponent.getHumanTaskServer().getTaskEngine();
validateCaller(invokerUserName);
this.operationInvoker = engine.getDaoConnectionFactory().getConnection().
createNewOrgEntityObject(invokerUserName, OrganizationalEntityDAO.OrganizationalEntityType.USER);
this.task = engine.getDaoConnectionFactory().getConnection().getTask(taskId);
validateTenant(invokerUserName);
if(this.task != null) {
this.event = engine.getDaoConnectionFactory().getConnection().createNewEventObject(task);
}
}
//checks the method caller is an actual user existing in the user store.
private void validateCaller(String callerId) {
if (StringUtils.isEmpty(callerId) || !engine.getPeopleQueryEvaluator().isExistingUser(callerId)) {
String errMsg = "The caller[name:" + callerId + "] is not a valid user in the user store.";
log.error(errMsg);
throw new HumanTaskIllegalArgumentException(errMsg);
}
}
private void validateTenant(String callerId) {
int tenantId = CarbonContext.getThreadLocalCarbonContext().getTenantId();
if (this.task != null) {
if (tenantId == task.getTenantId()) {
return;
} else {
log.error(callerId + " can't perform other tenant's task");
throw new HumanTaskIllegalAccessException("Access Denied. You are not authorized to perform this task");
}
}
}
/**
* Checks whether the this task is a valid task of TASK.
*/
public void checkForValidTask() {
if (task == null) {
throw new HumanTaskRuntimeException("The task is not loaded properly");
}
if (!TaskType.TASK.equals(task.getType())) {
String errMsg = String.format("The task[%d] is a notification, hence cannot perform [%s].",
task.getId(), this.getClass().getSimpleName());
log.error(errMsg);
throw new HumanTaskIllegalArgumentException(errMsg);
}
}
/**
* Checks whether the this task is a valid task of TASK.
*/
public void checkForValidNotification() {
if (task == null) {
throw new HumanTaskRuntimeException("The task is not loaded properly");
}
if (!TaskType.NOTIFICATION.equals(task.getType())) {
String errMsg = String.format("The task[%d] is a task, hence cannot perform [%s].",
task.getId(), this.getClass().getSimpleName());
log.error(errMsg);
throw new HumanTaskIllegalOperationException(errMsg);
}
}
/**
* Checks the post state of a task after a command execution
*
* @param expectedStatus : The expected post state.
*/
protected void checkPostState(TaskStatus expectedStatus) {
if (!expectedStatus.equals(task.getStatus())) {
String errMsg = String.format("Operation [%s] was not successfully performed on task[id: %d]" +
" as it's state is still in[%s]", this.getClass().getSimpleName(),
task.getId(), task.getStatus());
log.error(errMsg);
throw new HumanTaskIllegalStateException(errMsg);
}
}
/**
* A common method shared across all the commands to check the expected state of the
* task before the task operation is performed.
*
* @param expectedStatus : The expected pre state.
*/
protected void checkPreState(TaskStatus expectedStatus) {
if (!expectedStatus.equals(task.getStatus())) {
String errMsg = String.format("User[%s] cannot [%s] task[id:%d] as the task is in state[%s]. " +
"[%s] operation can be performed on tasks in state[%s]!",
operationInvoker.getName(), this.getClass().getSimpleName(), task.getId(),
task.getStatus(), this.getClass().getSimpleName(),
expectedStatus);
log.error(errMsg);
throw new HumanTaskIllegalStateException(errMsg);
}
}
/**
* A common method shared across all the commands to check the expected state of the
* task before the task operation is performed.
*
* @param expectedStates : The expected pre states.
*/
protected void checkPreStates(List<TaskStatus> expectedStates) {
if (!expectedStates.contains(task.getStatus())) {
String errMsg = String.format("User[%s] cannot [%s] task[id:%d] as the task is in state[%s]. " +
"[%s] operation can be performed on tasks in states[%s]!",
operationInvoker.getName(), this.getClass().getSimpleName(), task.getId(),
task.getStatus(), this.getClass().getSimpleName(),
expectedStates);
log.error(errMsg);
throw new HumanTaskIllegalStateException(errMsg);
}
}
protected void authoriseRoles(List<GenericHumanRoleDAO.GenericHumanRoleType> allowedRoles) {
if (!OperationAuthorizationUtil.authoriseUser(this.task, operationInvoker, allowedRoles,
engine.getPeopleQueryEvaluator())) {
String errorMsg = String.format("The user[%s] cannot perform [%s]" +
" operation as either he is in EXCLUDED_OWNERS role or he is not in task roles [%s]",
operationInvoker.getName(), this.getClass().getSimpleName(),
allowedRoles);
log.error(errorMsg);
throw new HumanTaskIllegalAccessException("Access Denied. You are not authorized to perform this task");
}
}
protected void reloadTask() {
this.task = engine.getDaoConnectionFactory().getConnection().getTask(task.getId());
}
/**
* Checks the Pre-conditions before executing the task operation.
*/
protected abstract void checkPreConditions();
/**
* Perform the authorization checks before executing the task operation.
*/
protected abstract void authorise();
/**
* Perform the state checks before executing the task operation.
*/
protected abstract void checkState();
/**
* Checks the post-conditions after executing the task operation.
*/
protected abstract void checkPostConditions();
/**
* Creates the task event object corresponding the the command being executed.
*
* @return : The task event object.
*/
protected EventDAO createTaskEvent() {
event.setTask(task);
//As the getClass method gives the run time class name we can directly set the operation type.
event.setType(TaskEventType.valueOf(this.getClass().getSimpleName().toUpperCase()));
event.setUser(operationInvoker.getName());
event.setNewState(task.getStatus());
return event;
}
/**
* @return : Returns the empty event object.
* Note the calling child object should fill all the fields properly.
*/
protected EventDAO getTaskEvent() {
return event;
}
/**
*
*/
protected void processTaskEvent() {
EventDAO eventDAO = createTaskEvent();
getTask().persistEvent(eventDAO);
TaskEventInfo taskEventInfo = CommonTaskUtil.populateTaskEventInfo(eventDAO, task);
getEngine().getEventProcessor().processEvent(taskEventInfo);
}
private void validateForExcludedOwner(String callerId) {
if(isExcludedOwner(callerId))
{
String errorMessage = "Access Denied. You are not authorized to access this task";
log.error("Current user " + callerId + " is in EXCLUDED_OWNERS role");
throw new HumanTaskIllegalAccessException(errorMessage);
}
}
protected boolean isExcludedOwner(String callerId) {
GenericHumanRoleDAO excludedOwnerRole = task.getGenericHumanRole(GenericHumanRoleDAO.GenericHumanRoleType.EXCLUDED_OWNERS);
if (excludedOwnerRole != null) {
List<OrganizationalEntityDAO> orgEntities = excludedOwnerRole.getOrgEntities();
for (OrganizationalEntityDAO orgEntity : orgEntities) {
if (orgEntity.getOrgEntityType() == OrganizationalEntityDAO.OrganizationalEntityType.USER &&
orgEntity.getName().equals(callerId)) {
return true;
} else if (orgEntity.getOrgEntityType() == OrganizationalEntityDAO.OrganizationalEntityType.GROUP) {
List<String> roleNameListForUser = engine.getPeopleQueryEvaluator().getRoleNameListForUser(callerId);
for (String roleName : roleNameListForUser) {
String orgEntityName = orgEntity.getName();
if (roleName.equals(orgEntityName)) {
return true;
}
}
}
}
}
return false;
}
}