001/* 002 * Copyright 2023 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.workflow.dao; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.Map.Entry; 023import java.util.Set; 024 025import org.apache.avalon.framework.component.Component; 026import org.apache.avalon.framework.service.ServiceException; 027import org.apache.avalon.framework.service.ServiceManager; 028import org.apache.avalon.framework.service.Serviceable; 029import org.apache.commons.lang3.StringUtils; 030 031import org.ametys.core.ui.Callable; 032import org.ametys.plugins.workflow.support.WorflowRightHelper; 033import org.ametys.plugins.workflow.support.WorkflowSessionHelper; 034import org.ametys.runtime.plugin.component.AbstractLogEnabled; 035 036import com.opensymphony.workflow.loader.ActionDescriptor; 037import com.opensymphony.workflow.loader.StepDescriptor; 038import com.opensymphony.workflow.loader.WorkflowDescriptor; 039 040/** 041 * DAO for workflow element's meta attributes 042 */ 043public class WorkflowPropertyDAO extends AbstractLogEnabled implements Component, Serviceable 044{ 045 /** The workflow session helper */ 046 protected WorkflowSessionHelper _workflowSessionHelper; 047 048 /** The workflow right helper */ 049 protected WorflowRightHelper _workflowRightHelper; 050 051 /** The workflow step DAO */ 052 protected WorkflowStepDAO _workflowStepDAO; 053 054 /** The workflow transition DAO */ 055 protected WorkflowTransitionDAO _workflowTransitionDAO; 056 057 public void service(ServiceManager smanager) throws ServiceException 058 { 059 _workflowSessionHelper = (WorkflowSessionHelper) smanager.lookup(WorkflowSessionHelper.ROLE); 060 _workflowRightHelper = (WorflowRightHelper) smanager.lookup(WorflowRightHelper.ROLE); 061 _workflowStepDAO = (WorkflowStepDAO) smanager.lookup(WorkflowStepDAO.ROLE); 062 _workflowTransitionDAO = (WorkflowTransitionDAO) smanager.lookup(WorkflowTransitionDAO.ROLE); 063 } 064 065 /** 066 * Get properties of current step 067 * @param workflowName the workflow unique name 068 * @param stepId id of the current step 069 * @return a map of the properties 070 */ 071 @SuppressWarnings("unchecked") 072 @Callable(rights = Callable.SKIP_BUILTIN_CHECK) 073 public Map<String, Object> getStepProperties(String workflowName, Integer stepId) 074 { 075 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, false); 076 List<Map<String, Object>> properties2json = new ArrayList<>(); 077 if (_workflowRightHelper.canRead(workflowDescriptor)) 078 { 079 StepDescriptor step = workflowDescriptor.getStep(stepId); 080 if (step != null) 081 { 082 properties2json.addAll(_properties2JSON(step.getMetaAttributes())); 083 } 084 } 085 086 return Map.of("data", properties2json); 087 } 088 089 /** 090 * Get properties of current action 091 * @param workflowName the workflow unique name 092 * @param actionId id of the current action 093 * @return a map of the properties 094 */ 095 @SuppressWarnings("unchecked") 096 @Callable(rights = Callable.SKIP_BUILTIN_CHECK) 097 public Map<String, Object> getActionProperties(String workflowName, Integer actionId) 098 { 099 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, false); 100 List<Map<String, Object>> propertiesToJson = new ArrayList<>(); 101 if (_workflowRightHelper.canRead(workflowDescriptor)) 102 { 103 ActionDescriptor action = workflowDescriptor.getAction(actionId); 104 if (action != null) 105 { 106 propertiesToJson.addAll(_properties2JSON(action.getMetaAttributes())); 107 } 108 } 109 110 return Map.of("data", propertiesToJson); 111 } 112 113 private List<Map<String, Object>> _properties2JSON(Map<String, Object> metaAttributes) 114 { 115 List<Map<String, Object>> propertiesToJson = new ArrayList<>(); 116 117 for (Entry<String, Object> entry : metaAttributes.entrySet()) 118 { 119 Map<String, Object> properties = new HashMap<>(); 120 properties.put("id", entry.getKey()); 121 properties.put("value", entry.getValue()); 122 propertiesToJson.add(properties); 123 } 124 125 return propertiesToJson; 126 } 127 128 /** 129 * Get the used property names for current workflow element 130 * @param workflowName unique name of current workflow 131 * @param stepId id of current step 132 * @param actionId id of current action, can be null if only a step is selected 133 * @return a set of the properties' names 134 */ 135 @Callable(rights = Callable.SKIP_BUILTIN_CHECK) 136 public Set<String> getPropertiesNames(String workflowName, Integer stepId, Integer actionId) 137 { 138 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, false); 139 _workflowRightHelper.checkEditRight(workflowDescriptor); 140 Map<String, Object> properties = _getProperties(workflowDescriptor, stepId, actionId); 141 return properties.keySet(); 142 } 143 144 /** 145 * Add a property to a workflow element 146 * @param workflowName unique name of current workflow 147 * @param stepId id of current step 148 * @param actionId id of current action, can be null if only a step is selected 149 * @param name the new name to save 150 * @param value the value to save 151 * @return the property's infos or an error message 152 */ 153 @Callable(rights = Callable.SKIP_BUILTIN_CHECK) 154 public Map<String, Object> addProperty(String workflowName, Integer stepId, Integer actionId, String name, String value) 155 { 156 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, true); 157 _workflowRightHelper.checkEditRight(workflowDescriptor); 158 if (StringUtils.isBlank(name)) 159 { 160 return Map.of("message", "blank-name"); 161 } 162 Map<String, Object> properties = _getProperties(workflowDescriptor, stepId, actionId); 163 if (properties.get(name) != null) 164 { 165 return Map.of("message", "duplicate-name"); 166 } 167 properties.put(name, value); 168 _workflowSessionHelper.updateWorkflowDescriptor(workflowDescriptor); 169 170 return _getPropertiesInfos(workflowDescriptor, stepId, actionId, name, value, true); 171 } 172 173 /** 174 * Edit property in a workflow element 175 * @param workflowName unique name of current workflow 176 * @param stepId id of current step 177 * @param actionId id of current action, can be null if only a step is selected 178 * @param oldName the old name for this property 179 * @param newName the new name to save 180 * @param newValue the value to save 181 * @return the property's infos or an error message 182 */ 183 @Callable(rights = Callable.SKIP_BUILTIN_CHECK) 184 public Map<String, Object> editProperty(String workflowName, Integer stepId, Integer actionId, String oldName, String newName, String newValue) 185 { 186 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, true); 187 _workflowRightHelper.checkEditRight(workflowDescriptor); 188 if (StringUtils.isBlank(newName)) 189 { 190 return Map.of("message", "blank-name"); 191 } 192 193 Map<String, Object> properties = _getProperties(workflowDescriptor, stepId, actionId); 194 195 if (StringUtils.isNotBlank(oldName) && !oldName.equals(newName)) 196 { 197 properties.remove(oldName); 198 } 199 properties.put(newName, newValue); 200 _workflowSessionHelper.updateWorkflowDescriptor(workflowDescriptor); 201 202 return _getPropertiesInfos(workflowDescriptor, stepId, actionId, newName, newValue, true); 203 } 204 205 /** 206 * Remove a property from a workflow element 207 * @param workflowName unique name of current workflow 208 * @param stepId id of current step 209 * @param actionId id of current action, can be null if only a step is selected 210 * @param name the new name to save 211 * @return the property's parent infos or an error message 212 */ 213 @Callable(rights = Callable.SKIP_BUILTIN_CHECK) 214 public Map<String, Object> deleteProperty(String workflowName, Integer stepId, Integer actionId, String name) 215 { 216 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, true); 217 _workflowRightHelper.checkEditRight(workflowDescriptor); 218 if (StringUtils.isBlank(name)) 219 { 220 return Map.of("message", "blank-name"); 221 } 222 223 Map<String, Object> properties = _getProperties(workflowDescriptor, stepId, actionId); 224 properties.remove(name); 225 _workflowSessionHelper.updateWorkflowDescriptor(workflowDescriptor); 226 227 return _getPropertiesInfos(workflowDescriptor, stepId, actionId, name, null, true); 228 } 229 230 private Map<String, Object> _getProperties(WorkflowDescriptor workflowDescriptor, Integer stepId, Integer actionId) 231 { 232 Map<String, Object> metaAttributes = new HashMap<>(); 233 234 if (actionId == null) 235 { 236 StepDescriptor step = workflowDescriptor.getStep(stepId); 237 metaAttributes = step.getMetaAttributes(); 238 } 239 else 240 { 241 ActionDescriptor action = workflowDescriptor.getAction(actionId); 242 metaAttributes = action.getMetaAttributes(); 243 } 244 245 return metaAttributes; 246 } 247 248 private Map<String, Object> _getPropertiesInfos(WorkflowDescriptor workflow, Integer stepId, Integer actionId, String name, String value, boolean hasChanges) 249 { 250 Map<String, Object> results = new HashMap<>(); 251 results.put("workflowId", workflow.getName()); 252 results.put("hasChanges", hasChanges); 253 results.put("stepId", stepId); 254 results.put("stepLabel", _workflowStepDAO.getStepLabel(workflow, stepId)); 255 if (actionId != null) 256 { 257 ActionDescriptor action = workflow.getAction(actionId); 258 results.put("actionId", actionId); 259 results.put("actionLabel", _workflowTransitionDAO.getActionLabel(action)); 260 } 261 results.put("name", name); 262 results.put("value", value); 263 return results; 264 } 265 266}