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.CHECKED_BY_IMPLEMENTATION) 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.CHECKED_BY_IMPLEMENTATION) 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.CHECKED_BY_IMPLEMENTATION) 136 public Set<String> getPropertiesNames(String workflowName, Integer stepId, Integer actionId) 137 { 138 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, false); 139 140 // Check user right 141 _workflowRightHelper.checkEditRight(workflowDescriptor); 142 143 Map<String, Object> properties = _getProperties(workflowDescriptor, stepId, actionId); 144 return properties.keySet(); 145 } 146 147 /** 148 * Add a property to a workflow element 149 * @param workflowName unique name of current workflow 150 * @param stepId id of current step 151 * @param actionId id of current action, can be null if only a step is selected 152 * @param name the new name to save 153 * @param value the value to save 154 * @return the property's infos or an error message 155 */ 156 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 157 public Map<String, Object> addProperty(String workflowName, Integer stepId, Integer actionId, String name, String value) 158 { 159 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, true); 160 161 // Check user right 162 _workflowRightHelper.checkEditRight(workflowDescriptor); 163 164 if (StringUtils.isBlank(name)) 165 { 166 return Map.of("message", "blank-name"); 167 } 168 Map<String, Object> properties = _getProperties(workflowDescriptor, stepId, actionId); 169 if (properties.get(name) != null) 170 { 171 return Map.of("message", "duplicate-name"); 172 } 173 properties.put(name, value); 174 _workflowSessionHelper.updateWorkflowDescriptor(workflowDescriptor); 175 176 return _getPropertiesInfos(workflowDescriptor, stepId, actionId, name, value, true); 177 } 178 179 /** 180 * Edit property in a workflow element 181 * @param workflowName unique name of current workflow 182 * @param stepId id of current step 183 * @param actionId id of current action, can be null if only a step is selected 184 * @param oldName the old name for this property 185 * @param newName the new name to save 186 * @param newValue the value to save 187 * @return the property's infos or an error message 188 */ 189 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 190 public Map<String, Object> editProperty(String workflowName, Integer stepId, Integer actionId, String oldName, String newName, String newValue) 191 { 192 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, true); 193 194 // Check user right 195 _workflowRightHelper.checkEditRight(workflowDescriptor); 196 197 if (StringUtils.isBlank(newName)) 198 { 199 return Map.of("message", "blank-name"); 200 } 201 202 Map<String, Object> properties = _getProperties(workflowDescriptor, stepId, actionId); 203 204 if (StringUtils.isNotBlank(oldName) && !oldName.equals(newName)) 205 { 206 properties.remove(oldName); 207 } 208 properties.put(newName, newValue); 209 _workflowSessionHelper.updateWorkflowDescriptor(workflowDescriptor); 210 211 return _getPropertiesInfos(workflowDescriptor, stepId, actionId, newName, newValue, true); 212 } 213 214 /** 215 * Remove a property from a workflow element 216 * @param workflowName unique name of current workflow 217 * @param stepId id of current step 218 * @param actionId id of current action, can be null if only a step is selected 219 * @param name the new name to save 220 * @return the property's parent infos or an error message 221 */ 222 @Callable(rights = Callable.CHECKED_BY_IMPLEMENTATION) 223 public Map<String, Object> deleteProperty(String workflowName, Integer stepId, Integer actionId, String name) 224 { 225 WorkflowDescriptor workflowDescriptor = _workflowSessionHelper.getWorkflowDescriptor(workflowName, true); 226 227 // Check user right 228 _workflowRightHelper.checkEditRight(workflowDescriptor); 229 230 if (StringUtils.isBlank(name)) 231 { 232 return Map.of("message", "blank-name"); 233 } 234 235 Map<String, Object> properties = _getProperties(workflowDescriptor, stepId, actionId); 236 properties.remove(name); 237 _workflowSessionHelper.updateWorkflowDescriptor(workflowDescriptor); 238 239 return _getPropertiesInfos(workflowDescriptor, stepId, actionId, name, null, true); 240 } 241 242 private Map<String, Object> _getProperties(WorkflowDescriptor workflowDescriptor, Integer stepId, Integer actionId) 243 { 244 Map<String, Object> metaAttributes = new HashMap<>(); 245 246 if (actionId == null) 247 { 248 StepDescriptor step = workflowDescriptor.getStep(stepId); 249 metaAttributes = step.getMetaAttributes(); 250 } 251 else 252 { 253 ActionDescriptor action = workflowDescriptor.getAction(actionId); 254 metaAttributes = action.getMetaAttributes(); 255 } 256 257 return metaAttributes; 258 } 259 260 private Map<String, Object> _getPropertiesInfos(WorkflowDescriptor workflow, Integer stepId, Integer actionId, String name, String value, boolean hasChanges) 261 { 262 Map<String, Object> results = new HashMap<>(); 263 results.put("workflowId", workflow.getName()); 264 results.put("hasChanges", hasChanges); 265 results.put("stepId", stepId); 266 results.put("stepLabel", _workflowStepDAO.getStepLabel(workflow, stepId)); 267 if (actionId != null) 268 { 269 ActionDescriptor action = workflow.getAction(actionId); 270 results.put("actionId", actionId); 271 results.put("actionLabel", _workflowTransitionDAO.getActionLabel(action)); 272 } 273 results.put("name", name); 274 results.put("value", value); 275 return results; 276 } 277 278}