/* * Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you 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.identity.workflow.impl.util; import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMAttribute; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMFactory; import org.apache.axiom.om.OMNamespace; import org.apache.commons.lang.StringUtils; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.identity.workflow.impl.WFImplConstant; import org.wso2.carbon.identity.workflow.mgt.bean.Parameter; import org.wso2.carbon.identity.workflow.mgt.bean.RequestParameter; import org.wso2.carbon.identity.workflow.mgt.dto.WorkflowRequest; import org.wso2.carbon.identity.workflow.mgt.exception.WorkflowException; import org.wso2.carbon.identity.workflow.mgt.util.WFConstant; import org.wso2.carbon.identity.workflow.mgt.util.WorkflowDataType; import org.wso2.carbon.identity.workflow.mgt.util.WorkflowManagementUtil; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public class WorkflowRequestBuilder { private static final String WF_NS = "http://schema.bpel.mgt.workflow.carbon.wso2.org/"; private static final String WF_NS_PREFIX = "p"; private static final String WF_REQ_ROOT_ELEM = "ProcessRequest"; private static final String WF_REQ_UUID_ELEM = "uuid"; private static final String WF_REQ_ACTION_ELEM = "eventType"; private static final String WF_REQ_TASK_INITIATOR_ELEM = "taskInitiator"; private static final String WF_REQ_CONFIG_ELEM = "configuration"; private static final String WF_REQ_APPROVAL_STEP_ELEM = "approvalStep"; private static final String WF_REQ_STEP_NAME_ELEM = "stepName"; private static final String WF_REQ_HUMAN_TASK_ELEM = "humanTask"; private static final String WF_REQ_HUMAN_TASK_SUBJECT_ELEM = "humanTaskSubject"; private static final String WF_REQ_HUMAN_TASK_DESC_ELEM = "humanTaskDescription"; private static final String WF_REQ_APPROVE_USER_ELEM = "user"; private static final String WF_REQ_APPROVE_ROLE_ELEM = "role"; // private static final String WF_REQ_TENANT_DOMAIN_ELEM = "tenantDomain"; private static final String WF_REQ_PARAMS_ELEM = "parameters"; private static final String WF_REQ_PARAM_ELEM = "parameter"; private static final String WF_REQ_PARAM_NAME_ATTRIB = "name"; private static final String WF_REQ_LIST_ITEM_ELEM = "itemValue"; private static final String WF_REQ_KEY_ATTRIB = "itemName"; private static final String WF_REQ_VALUE_ELEM = "value"; private static final Set<Class> SUPPORTED_CLASS_TYPES; static { //only following types of objects will be allowed as values to the parameters. SUPPORTED_CLASS_TYPES = new HashSet<>(); SUPPORTED_CLASS_TYPES.add(String.class); SUPPORTED_CLASS_TYPES.add(Integer.class); SUPPORTED_CLASS_TYPES.add(Double.class); SUPPORTED_CLASS_TYPES.add(Float.class); SUPPORTED_CLASS_TYPES.add(Long.class); SUPPORTED_CLASS_TYPES.add(Character.class); SUPPORTED_CLASS_TYPES.add(Byte.class); SUPPORTED_CLASS_TYPES.add(Short.class); SUPPORTED_CLASS_TYPES.add(Boolean.class); } private String uuid; private String event; private Map<String, Object> singleValuedParams; private Map<String, List<Object>> listTypeParams; private Map<String, Map<String, Object>> mapTypeParams; private List<Parameter> parameterList; /** * Create OM Element with workflow object * * @param workFlowRequest Request to be converted to OM Element * @return * @throws WorkflowException */ public static OMElement buildXMLRequest(WorkflowRequest workFlowRequest) throws WorkflowException { WorkflowRequestBuilder requestBuilder = new WorkflowRequestBuilder(workFlowRequest.getUuid(), workFlowRequest.getEventType()); for (RequestParameter parameter : workFlowRequest.getRequestParameters()) { if (parameter.isRequiredInWorkflow()) { switch (parameter.getValueType()) { case WorkflowDataType.BOOLEAN_TYPE: case WorkflowDataType.STRING_TYPE: case WorkflowDataType.INTEGER_TYPE: case WorkflowDataType.DOUBLE_TYPE: requestBuilder.addSingleValuedParam(parameter.getName(), parameter.getValue()); break; case WorkflowDataType.STRING_LIST_TYPE: case WorkflowDataType.DOUBLE_LIST_TYPE: case WorkflowDataType.INTEGER_LIST_TYPE: case WorkflowDataType.BOOLEAN_LIST_TYPE: requestBuilder.addListTypeParam(parameter.getName(), (List<Object>) parameter.getValue()); break; case WorkflowDataType.STRING_STRING_MAP_TYPE: requestBuilder.addMapTypeParam(parameter.getName(), (Map<String, Object>) parameter.getValue()); break; //ignoring the other types } } } return requestBuilder.buildRequest(); } /** * Create OM Element with workflow object * * @param workFlowRequest Request to be converted to OM Element * @param parameterList Workflow parameter list * @return * @throws WorkflowException */ public static OMElement buildXMLRequest(WorkflowRequest workFlowRequest, List<Parameter> parameterList) throws WorkflowException { WorkflowRequestBuilder requestBuilder = new WorkflowRequestBuilder(workFlowRequest.getUuid(), workFlowRequest.getEventType()); for (RequestParameter parameter : workFlowRequest.getRequestParameters()) { if (parameter.isRequiredInWorkflow()) { switch (parameter.getValueType()) { case WorkflowDataType.BOOLEAN_TYPE: case WorkflowDataType.STRING_TYPE: case WorkflowDataType.INTEGER_TYPE: case WorkflowDataType.DOUBLE_TYPE: requestBuilder.addSingleValuedParam(parameter.getName(), parameter.getValue()); break; case WorkflowDataType.STRING_LIST_TYPE: case WorkflowDataType.DOUBLE_LIST_TYPE: case WorkflowDataType.INTEGER_LIST_TYPE: case WorkflowDataType.BOOLEAN_LIST_TYPE: requestBuilder.addListTypeParam(parameter.getName(), (List<Object>) parameter.getValue()); break; case WorkflowDataType.STRING_STRING_MAP_TYPE: requestBuilder.addMapTypeParam(parameter.getName(), (Map<String, Object>) parameter.getValue ()); break; //ignoring the other types } } } requestBuilder.setInitParams(parameterList); return requestBuilder.buildRequest(); } public void setInitParams(List<Parameter> parameterList) { this.parameterList = parameterList; } /** * Initialize the Request builder with uuid and event * * @param uuid Uniquely identifies the workflow * @param action The identifier for the event for which the workflow was triggered */ public WorkflowRequestBuilder(String uuid, String action) { this.uuid = uuid; this.event = action; singleValuedParams = new HashMap<>(); listTypeParams = new HashMap<>(); mapTypeParams = new HashMap<>(); this.parameterList = new ArrayList<>(); } /** * Adds a parameter with a single value. eg. tenantDomain="carbon.super" * * @param key The param name * @param value The param value, must be either a wrapper for a primitive or String * @return This builder instance */ public WorkflowRequestBuilder addSingleValuedParam(String key, Object value) throws WorkflowException { if (StringUtils.isNotBlank(key)) { if (isValidValue(value)) { singleValuedParams.put(key, value); return this; } else { throw new WorkflowException("Value provided for " + key + " is not acceptable. Use either " + "string, boolean, or numeric value"); } } else { throw new WorkflowException("Key cannot be null or empty"); } } /** * Check whether the given object is of valid type * * @param obj The object to be tested * @return */ protected boolean isValidValue(Object obj) { //null value of one of the supported class return obj == null || SUPPORTED_CLASS_TYPES.contains(obj.getClass()); } /** * Adds a parameter with a list value. eg. roleList={"admin","manager"} * * @param key The param name * @param value The param value list, each item must be either a wrapper for a primitive or String * @return This builder instance */ public WorkflowRequestBuilder addListTypeParam(String key, List<Object> value) throws WorkflowException { if (StringUtils.isNotBlank(key)) { if (value != null) { for (Object o : value) { if (!isValidValue(o)) { throw new WorkflowException( "At least one value provided for " + key + " is not acceptable" + ". Use either string, boolean, or numeric value"); } } listTypeParams.put(key, value); return this; } else { throw new WorkflowException("Value for " + key + " cannot be null"); } } else { throw new WorkflowException("Key cannot be null or empty"); } } /** * Adds a parameter with a map value. eg. claimList={"First Name" = "Joan","Last Name" = "Doe"} * * @param key The param name * @param value The param value map, each key of the map should be String, and each value must be either a wrapper * to a primitive or String * @return This builder instance */ public WorkflowRequestBuilder addMapTypeParam(String key, Map<String, Object> value) throws WorkflowException { if (StringUtils.isNotBlank(key)) { if (value != null) { for (Map.Entry<String, Object> entry : value.entrySet()) { if (StringUtils.isBlank(entry.getKey())) { throw new IllegalArgumentException("Map item's key value cannot be null"); } if (!isValidValue(entry.getValue())) { throw new WorkflowException( "Value provided for " + entry.getKey() + " is not acceptable" + ". Use either string, boolean, or numeric value"); } } mapTypeParams.put(key, value); return this; } else { throw new WorkflowException("Value for " + key + " cannot be null"); } } else { throw new WorkflowException("Key cannot be null or empty"); } } /** * Builds the SOAP request body for the Service endpoint * * @return */ public OMElement buildRequest() { OMFactory omFactory = OMAbstractFactory.getOMFactory(); OMNamespace omNs = omFactory.createOMNamespace(WF_NS, WF_NS_PREFIX); OMElement rootElement = omFactory.createOMElement(WF_REQ_ROOT_ELEM, omNs); OMElement uuidElement = omFactory.createOMElement(WF_REQ_UUID_ELEM, omNs); OMElement reqIdElement = omFactory.createOMElement(WF_REQ_ACTION_ELEM, omNs); OMElement taskInitiatorElement = omFactory.createOMElement(WF_REQ_TASK_INITIATOR_ELEM, omNs); OMElement configElement = omFactory.createOMElement(WF_REQ_CONFIG_ELEM, omNs); uuidElement.setText(uuid); rootElement.addChild(uuidElement); reqIdElement.setText(event); rootElement.addChild(reqIdElement); taskInitiatorElement.setText(CarbonContext.getThreadLocalCarbonContext().getUsername()); rootElement.addChild(taskInitiatorElement); OMElement paramsElement = omFactory.createOMElement(WF_REQ_PARAMS_ELEM, omNs); for (Map.Entry<String, Object> entry : singleValuedParams.entrySet()) { OMElement paramElement = omFactory.createOMElement(WF_REQ_PARAM_ELEM, omNs); OMAttribute paramNameAttribute = omFactory.createOMAttribute(WF_REQ_PARAM_NAME_ATTRIB, null, entry.getKey()); paramElement.addAttribute(paramNameAttribute); OMElement valueElement = omFactory.createOMElement(WF_REQ_VALUE_ELEM, omNs); OMElement valueItemElement = omFactory.createOMElement(WF_REQ_LIST_ITEM_ELEM, omNs); valueItemElement.setText(entry.getValue().toString()); valueElement.addChild(valueItemElement); paramElement.addChild(valueElement); paramsElement.addChild(paramElement); } for (Map.Entry<String, List<Object>> entry : listTypeParams.entrySet()) { OMElement paramElement = omFactory.createOMElement(WF_REQ_PARAM_ELEM, omNs); OMAttribute paramNameAttribute = omFactory.createOMAttribute(WF_REQ_PARAM_NAME_ATTRIB, null, entry.getKey()); paramElement.addAttribute(paramNameAttribute); OMElement valueElement = omFactory.createOMElement(WF_REQ_VALUE_ELEM, omNs); for (Object listItem : entry.getValue()) { if (listItem != null) { OMElement listItemElement = omFactory.createOMElement(WF_REQ_LIST_ITEM_ELEM, omNs); listItemElement.setText(listItem.toString()); valueElement.addChild(listItemElement); } } paramElement.addChild(valueElement); paramsElement.addChild(paramElement); } for (Map.Entry<String, Map<String, Object>> entry : mapTypeParams.entrySet()) { OMElement paramElement = omFactory.createOMElement(WF_REQ_PARAM_ELEM, omNs); OMAttribute paramNameAttribute = omFactory.createOMAttribute(WF_REQ_PARAM_NAME_ATTRIB, null, entry.getKey()); paramElement.addAttribute(paramNameAttribute); OMElement valueElement = omFactory.createOMElement(WF_REQ_VALUE_ELEM, omNs); for (Map.Entry<String, Object> mapItem : entry.getValue().entrySet()) { if (mapItem.getKey() != null) { String valueText; if (mapItem.getValue() != null) { valueText = mapItem.getValue().toString(); } else { valueText = "Null"; } OMElement listItemElement = omFactory.createOMElement(WF_REQ_LIST_ITEM_ELEM, omNs); OMAttribute itemNameAttribute = omFactory.createOMAttribute(WF_REQ_KEY_ATTRIB, null, mapItem.getKey()); listItemElement.addAttribute(itemNameAttribute); listItemElement.setText(valueText); valueElement.addChild(listItemElement); } } paramElement.addChild(valueElement); paramsElement.addChild(paramElement); } rootElement.addChild(paramsElement); Parameter htParameter = WorkflowManagementUtil .getParameter(parameterList, WFImplConstant.ParameterName.HT_SUBJECT, WFConstant.ParameterHolder .WORKFLOW_IMPL); String ht = ""; if (htParameter != null) { ht = htParameter.getParamValue(); } Parameter htDescParameter = WorkflowManagementUtil .getParameter(parameterList, WFImplConstant.ParameterName.HT_DESCRIPTION, WFConstant.ParameterHolder .WORKFLOW_IMPL); String htDesc = ""; if (htDescParameter != null) { htDesc = htDescParameter.getParamValue(); } final Map<String, Map<String, List<String>>> approvalStepMap = getApprovalStepMap(); for (int a = 1; a <= approvalStepMap.size(); a++) { String key = "Step " + a; OMElement stepName = omFactory.createOMElement(WF_REQ_STEP_NAME_ELEM, omNs); stepName.setText(key); OMElement approvalStepElement = omFactory.createOMElement(WF_REQ_APPROVAL_STEP_ELEM, omNs); approvalStepElement.addChild(stepName); OMElement humanTaskElement = omFactory.createOMElement(WF_REQ_HUMAN_TASK_ELEM, omNs); OMElement humanTaskSubjectElement = omFactory.createOMElement(WF_REQ_HUMAN_TASK_SUBJECT_ELEM, omNs); humanTaskSubjectElement.setText(ht); OMElement humanTaskDescElement = omFactory.createOMElement(WF_REQ_HUMAN_TASK_DESC_ELEM, omNs); humanTaskDescElement.setText(htDesc); humanTaskElement.addChild(humanTaskSubjectElement); humanTaskElement.addChild(humanTaskDescElement); approvalStepElement.addChild(humanTaskElement); Map<String, List<String>> value = approvalStepMap.get(a + ""); if (value.get("users") != null) { List<String> userList = value.get("users"); for (String user : userList) { OMElement userElement = omFactory.createOMElement(WF_REQ_APPROVE_USER_ELEM, omNs); userElement.setText(user); approvalStepElement.addChild(userElement); } } if (value.get("roles") != null) { List<String> userList = value.get("roles"); for (String user : userList) { OMElement userElement = omFactory.createOMElement(WF_REQ_APPROVE_ROLE_ELEM, omNs); userElement.setText(user); approvalStepElement.addChild(userElement); } } configElement.addChild(approvalStepElement); } rootElement.addChild(configElement); return rootElement; } private Map<String, Map<String, List<String>>> getApprovalStepMap() { Map<String, Map<String, List<String>>> map = new HashMap<String, Map<String, List<String>>>(); for (Parameter parameter : this.parameterList) { if (parameter.getParamName().equals(WFImplConstant.ParameterName.STEPS_USER_AND_ROLE)) { String[] key = parameter.getqName().split("-"); String step = key[2]; Map<String, List<String>> valueMap = map.get(step); if (valueMap == null) { valueMap = new HashMap<String, List<String>>(); map.put(step, valueMap); } String value = parameter.getParamValue(); String[] values = null; if (StringUtils.isNotBlank(value)) { values = value.split(","); } if (values != null) { List<String> userList = Arrays.asList(values); String stepName = WFImplConstant.ParameterName.STEPS_USER_AND_ROLE + "-step-" + step + "-users"; if (stepName.equals(parameter.getqName())) { valueMap.put("users", userList); } stepName = WFImplConstant.ParameterName.STEPS_USER_AND_ROLE + "-step-" + step + "-roles"; if (stepName.equals(parameter.getqName())) { valueMap.put("roles", userList); } } } } return map; } }