001/*
002 *  Copyright 2015 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.cms.search.systemprop;
017
018import java.util.LinkedHashMap;
019import java.util.List;
020import java.util.Map;
021
022import org.apache.avalon.framework.configuration.Configuration;
023import org.apache.avalon.framework.configuration.DefaultConfiguration;
024import org.apache.avalon.framework.service.ServiceException;
025import org.apache.avalon.framework.service.ServiceManager;
026import org.apache.cocoon.xml.AttributesImpl;
027import org.apache.cocoon.xml.XMLUtils;
028import org.xml.sax.ContentHandler;
029import org.xml.sax.SAXException;
030
031import org.ametys.cms.contenttype.MetadataType;
032import org.ametys.cms.repository.Content;
033import org.ametys.cms.repository.WorkflowAwareContent;
034import org.ametys.cms.search.SearchField;
035import org.ametys.cms.search.model.SystemProperty;
036import org.ametys.cms.search.query.Query;
037import org.ametys.cms.search.query.Query.Operator;
038import org.ametys.cms.search.query.WorkflowStepQuery;
039import org.ametys.cms.search.solr.field.WorkflowStepSearchField;
040import org.ametys.cms.workflow.DefaultWorkflowStepEnumerator;
041import org.ametys.plugins.workflow.support.WorkflowHelper;
042import org.ametys.plugins.workflow.support.WorkflowProvider;
043import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow;
044import org.ametys.runtime.i18n.I18nizableText;
045
046import com.opensymphony.workflow.loader.StepDescriptor;
047import com.opensymphony.workflow.loader.WorkflowDescriptor;
048import com.opensymphony.workflow.spi.Step;
049
050/**
051 * {@link SystemProperty} which represents the current workflow step ID of a content.
052 */
053public class WorkflowStepSystemProperty extends AbstractSystemProperty
054{
055    /** The workflow provider */
056    protected WorkflowProvider _workflowProvider;
057    
058    /** The workflow helper */
059    protected WorkflowHelper _workflowHelper;
060    
061    @Override
062    public void service(ServiceManager manager) throws ServiceException
063    {
064        super.service(manager);
065        _workflowProvider = (WorkflowProvider) manager.lookup(WorkflowProvider.ROLE);
066        _workflowHelper = (WorkflowHelper) manager.lookup(WorkflowHelper.ROLE);
067    }
068    
069    @Override
070    public MetadataType getType()
071    {
072        return MetadataType.LONG;
073    }
074    
075    @Override
076    public boolean isMultiple()
077    {
078        return false;
079    }
080    
081    @Override
082    public boolean isSortable()
083    {
084        return true;
085    }
086    
087    @Override
088    public Query getQuery(Object value, Operator operator, String language, Map<String, Object> contextualParameters)
089    {
090        long stepId = parseLong(value);
091        if (stepId != 0)
092        {
093            return new WorkflowStepQuery(operator, (int) stepId);
094        }
095        
096        return null;
097    }
098    
099    @Override
100    public SearchField getSearchField()
101    {
102        return new WorkflowStepSearchField();
103    }
104    
105    @Override
106    public String getRenderer()
107    {
108        return "Ametys.plugins.cms.search.SearchGridHelper.renderWorkflowStep";
109    }
110    
111    @Override
112    public String getConverter()
113    {
114        return "Ametys.plugins.cms.search.SearchGridHelper.convertWorkflowStep";
115    }
116    
117    @Override
118    public Integer getColumnWidth()
119    {
120        return 60;
121    }
122    
123    @Override
124    public Object getValue(Content content)
125    {
126        if (content instanceof WorkflowAwareContent)
127        {
128            WorkflowAwareContent waContent = (WorkflowAwareContent) content;
129            AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(waContent);
130            
131            long workflowId = waContent.getWorkflowId();
132            List<Step> currentSteps = workflow.getCurrentSteps(workflowId);
133            
134            if (!currentSteps.isEmpty())
135            {
136                return Long.valueOf(currentSteps.iterator().next().getStepId());
137            }
138        }
139        
140        return null;
141    }
142    
143    public Object getJsonValue(Content content, boolean full)
144    {
145        Long value = (Long) getValue(content);
146        if (value != null && full)
147        {
148            Map<String, Object> workflowInfos = new LinkedHashMap<>();
149            
150            if (content instanceof WorkflowAwareContent)
151            {
152                WorkflowAwareContent waContent = (WorkflowAwareContent) content;
153                int currentStepId = Math.toIntExact(value);
154                
155                StepDescriptor stepDescriptor = _getStepDescriptor(waContent, currentStepId);
156                
157                if (stepDescriptor != null)
158                {
159                    I18nizableText workflowStepName = new I18nizableText("application", stepDescriptor.getName());
160                    
161                    workflowInfos.put("stepId", currentStepId);
162                    workflowInfos.put("name", workflowStepName);
163                    
164                    String[] icons = new String[] {"small", "medium", "large"};
165                    for (String icon : icons)
166                    {
167                        if ("application".equals(workflowStepName.getCatalogue()))
168                        {
169                            workflowInfos.put(icon + "Icon", "/plugins/cms/resources_workflow/" + workflowStepName.getKey() + "-" + icon + ".png");
170                        }
171                        else
172                        {
173                            String pluginName = workflowStepName.getCatalogue().substring("plugin.".length());
174                            workflowInfos.put(icon + "Icon", "/plugins/" + pluginName + "/resources/img/workflow/" + workflowStepName.getKey() + "-" + icon + ".png");
175                        }
176                    }
177                }
178            }
179            
180            return workflowInfos;
181        }
182        return value;
183    }
184    
185    @Override
186    public void saxValue(ContentHandler handler, Content content) throws SAXException
187    {
188        Long value = (Long) getValue(content);
189        if (value != null && content instanceof WorkflowAwareContent)
190        {
191            WorkflowAwareContent waContent = (WorkflowAwareContent) content;
192            int currentStepId = Math.toIntExact(value);
193            
194            StepDescriptor stepDescriptor = _getStepDescriptor(waContent, currentStepId);
195            
196            if (stepDescriptor != null)
197            {
198                I18nizableText workflowStepName = new I18nizableText("application", stepDescriptor.getName());
199                
200                AttributesImpl attr = new AttributesImpl();
201                attr.addCDATAAttribute("id", String.valueOf(currentStepId));
202                XMLUtils.startElement(handler, getId(), attr);
203                workflowStepName.toSAX(handler);
204                XMLUtils.endElement(handler, getId());
205            }
206        }
207    }
208    
209    private StepDescriptor _getStepDescriptor(WorkflowAwareContent content, int stepId)
210    {
211        long workflowId = content.getWorkflowId();
212        
213        AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(content);
214        
215        String workflowName = workflow.getWorkflowName(workflowId);
216        WorkflowDescriptor workflowDescriptor = workflow.getWorkflowDescriptor(workflowName);
217        
218        if (workflowDescriptor != null)
219        {
220            StepDescriptor stepDescriptor = workflowDescriptor.getStep(stepId);
221            if (stepDescriptor != null)
222            {
223                return stepDescriptor;
224            }
225            else if (getLogger().isWarnEnabled())
226            {
227                getLogger().warn("Unknown step id '" + stepId + "' for workflow for name : " + workflowName);
228            }
229        }
230        else if (getLogger().isWarnEnabled())
231        {
232            getLogger().warn("Unknown workflow for name : " + workflowName);
233        }
234        
235        return null;
236    }
237    
238    @Override
239    public EnumeratorDefinition getEnumeratorDefinition(Configuration configuration)
240    {
241        DefaultConfiguration conf = new DefaultConfiguration("criteria");
242        
243        String workflowName = configuration.getChild("workflow").getAttribute("name", "content");
244        
245        DefaultConfiguration enumConf = new DefaultConfiguration("enumeration");
246        
247        DefaultConfiguration customEnumerator = new DefaultConfiguration("custom-enumerator");
248        customEnumerator.setAttribute("class", DefaultWorkflowStepEnumerator.class.getName());
249        enumConf.addChild(customEnumerator);
250        
251        DefaultConfiguration wfNameConf = new DefaultConfiguration("workflow-name");
252        wfNameConf.setValue(workflowName);
253        customEnumerator.addChild(wfNameConf);
254        
255        DefaultConfiguration excludeConf = new DefaultConfiguration("exclude-workflow-steps");
256        
257        // Exclude workflow steps greater than 9000
258        List<StepDescriptor> steps = _workflowHelper.getWorkflowDescriptor(workflowName).getSteps();
259        for (StepDescriptor stepDescriptor : steps)
260        {
261            if (stepDescriptor.getId() >= 9000)
262            {
263                DefaultConfiguration stepId = new DefaultConfiguration("id");
264                stepId.setValue(stepDescriptor.getId());
265                excludeConf.addChild(stepId);
266            }
267        }
268        
269        customEnumerator.addChild(excludeConf);
270        
271        conf.addChild(enumConf);
272        
273        return new EnumeratorDefinition(DefaultWorkflowStepEnumerator.class, conf);
274    }
275
276}