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.readers; 017 018import java.io.ByteArrayOutputStream; 019import java.io.IOException; 020import java.nio.charset.StandardCharsets; 021 022import org.apache.avalon.framework.service.ServiceException; 023import org.apache.avalon.framework.service.ServiceManager; 024import org.apache.avalon.framework.service.Serviceable; 025import org.apache.cocoon.ProcessingException; 026import org.apache.cocoon.environment.ObjectModelHelper; 027import org.apache.cocoon.environment.Request; 028import org.apache.cocoon.reading.AbstractReader; 029import org.apache.commons.io.IOUtils; 030import org.xml.sax.SAXException; 031 032import org.ametys.core.util.I18nUtils; 033import org.ametys.plugins.workflow.dao.WorkflowStepDAO; 034import org.ametys.plugins.workflow.support.WorkflowHelper; 035import org.ametys.runtime.i18n.I18nizableText; 036 037import com.opensymphony.workflow.loader.ActionDescriptor; 038import com.opensymphony.workflow.loader.StepDescriptor; 039import com.opensymphony.workflow.loader.WorkflowDescriptor; 040 041import net.sourceforge.plantuml.FileFormat; 042import net.sourceforge.plantuml.FileFormatOption; 043import net.sourceforge.plantuml.SourceStringReader; 044 045/** 046 * Abstract class for reading PlantUML SVG 047 */ 048public abstract class AbstractPlantUMLSVGReader extends AbstractReader implements Serviceable 049{ 050 /** The color for step nodes */ 051 protected static final String __MAIN_STEP_NODE_COLOR = "#e5f8ff"; 052 053 /** The workflow helper */ 054 protected WorkflowHelper _workflowHelper; 055 056 /** I18n Utils */ 057 protected I18nUtils _i18nUtils; 058 059 /** The workflow step DAO */ 060 protected WorkflowStepDAO _workflowStepDAO; 061 062 @Override 063 public void service(ServiceManager serviceManager) throws ServiceException 064 { 065 _workflowHelper = (WorkflowHelper) serviceManager.lookup(WorkflowHelper.ROLE); 066 _i18nUtils = (I18nUtils) serviceManager.lookup(I18nUtils.ROLE); 067 _workflowStepDAO = (WorkflowStepDAO) serviceManager.lookup(WorkflowStepDAO.ROLE); 068 } 069 070 @Override 071 public void generate() throws IOException, SAXException, ProcessingException 072 { 073 try 074 { 075 Request request = ObjectModelHelper.getRequest(objectModel); 076 String workflowName = (String) request.get("workflowName"); 077 078 WorkflowDescriptor workflowDescriptor = _workflowHelper.getWorkflowDescriptor(workflowName); 079 080 _setPlantUMLProperties(); 081 String content = _getPlantUMLContent(request, workflowDescriptor); 082 SourceStringReader reader = new SourceStringReader(content); 083 084 try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) 085 { 086 reader.outputImage(byteArrayOutputStream, new FileFormatOption(FileFormat.SVG).withSvgLinkTarget("_self")); 087 088 String svgContent = byteArrayOutputStream.toString(StandardCharsets.UTF_8); 089 svgContent = svgContent.replaceAll("<svg ", "<svg onclick=\"parent.Ametys.tool.ToolsManager.getTool('uitool-workflow-preview').focus();\" "); 090 091 IOUtils.write(svgContent, out, StandardCharsets.UTF_8); 092 } 093 } 094 finally 095 { 096 out.close(); 097 } 098 } 099 100 /** 101 * Set common plantUML svg properties 102 */ 103 protected void _setPlantUMLProperties() 104 { 105 System.setProperty("PLANTUML_ALLOW_JAVASCRIPT_IN_LINK", "true"); 106 System.setProperty("PLANTUML_LIMIT_SIZE", String.valueOf(Integer.MAX_VALUE)); 107 } 108 109 /** 110 * Get the PlantUML SVG content to read 111 * @param request the request 112 * @param workflowDescriptor descriptor of current workflow 113 * @return The content to read 114 */ 115 protected String _getPlantUMLContent(Request request, WorkflowDescriptor workflowDescriptor) 116 { 117 StringBuilder content = new StringBuilder("@start" + _getPlantUMLType() + "\n"); 118 content.append(_getPlantUMLStyle()); 119 content.append(_getPlantUMLGraphContent(request, workflowDescriptor)); 120 content.append("@end" + _getPlantUMLType()); 121 return content.toString(); 122 } 123 124 /** 125 * Get the diagram type 126 * @return the diagram type 127 */ 128 protected abstract String _getPlantUMLType(); 129 130 /** 131 * Get plantUML style for current diagram 132 * @return the style as string 133 */ 134 protected abstract String _getPlantUMLStyle(); 135 136 /** 137 * Get the plantUML diagram body 138 * @param request the request 139 * @param workflowDescriptor descriptor of current workflow 140 * @return the diagram body as string 141 */ 142 protected abstract String _getPlantUMLGraphContent(Request request, WorkflowDescriptor workflowDescriptor); 143 144 /** 145 * Get js function to send selection 146 * @param workflowName unique name of current workflow 147 * @param stepId current or incoming step's id 148 * @param actionId current action's, can be null 149 * @return the js function 150 */ 151 protected String _getJsFunction(String workflowName, String stepId, String actionId) 152 { 153 String jsParameters = "'" + workflowName + "','" + stepId; 154 jsParameters += actionId != null ? "','" + actionId + "'" : "'"; 155 return "Ametys.plugins.workflow.UI.UIWorkflowGraph.sendSelection(" + jsParameters + ")"; 156 } 157 158 /** 159 * Get the node label for step 160 * @param workflowDescriptor current workflow 161 * @param stepId current step id 162 * @return the node label which is the translated step name and its id 163 */ 164 protected String _getStepNodeLabel(WorkflowDescriptor workflowDescriptor, int stepId) 165 { 166 return _workflowStepDAO.getStepLabel(workflowDescriptor, stepId) + " (" + stepId + ")"; 167 } 168 169 /** 170 * Get the tooltip for a link on step 171 * @param step current step 172 * @return the tooltip 173 */ 174 protected String _getStepTooltip(StepDescriptor step) 175 { 176 return _i18nUtils.translate(new I18nizableText("plugin.workflow", "PLUGIN_WORKFLOW_LINK_SEE_STEP")); 177 } 178 179 /** 180 * Get the action label for node 181 * @param action current action 182 * @return the label as action's name and id 183 */ 184 protected String _getActionLabel(ActionDescriptor action) 185 { 186 return _workflowStepDAO.getActionLabel(action) + " (" + action.getId() + ")"; 187 } 188 189 /** 190 * Get the tooltip for a link on action 191 * @param action current action 192 * @return the tooltip 193 */ 194 protected String _getActionTooltip(ActionDescriptor action) 195 { 196 return _i18nUtils.translate(new I18nizableText("plugin.workflow", "PLUGIN_WORKFLOW_LINK_SEE_TRANSITION")); 197 } 198}