001/*
002 *  Copyright 2014 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.explorer.calendars.generators;
017
018import java.io.IOException;
019import java.time.ZonedDateTime;
020import java.time.format.DateTimeFormatter;
021import java.util.Date;
022import java.util.GregorianCalendar;
023import java.util.HashMap;
024import java.util.List;
025import java.util.Map;
026
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.cocoon.ProcessingException;
030import org.apache.cocoon.environment.ObjectModelHelper;
031import org.apache.cocoon.environment.Request;
032import org.apache.cocoon.generation.ServiceableGenerator;
033import org.apache.cocoon.xml.AttributesImpl;
034import org.apache.cocoon.xml.XMLUtils;
035import org.apache.commons.lang.StringUtils;
036import org.xml.sax.SAXException;
037
038import org.ametys.core.user.User;
039import org.ametys.core.user.UserIdentity;
040import org.ametys.core.user.UserManager;
041import org.ametys.plugins.explorer.calendars.Calendar;
042import org.ametys.plugins.explorer.calendars.CalendarEvent;
043import org.ametys.plugins.explorer.workflow.AbstractExplorerNodeWorkflowComponent;
044import org.ametys.plugins.repository.AmetysObject;
045import org.ametys.plugins.repository.AmetysObjectResolver;
046import org.ametys.plugins.repository.ModifiableAmetysObject;
047import org.ametys.plugins.repository.RemovableAmetysObject;
048import org.ametys.plugins.workflow.support.WorkflowHelper;
049import org.ametys.plugins.workflow.support.WorkflowProvider;
050import org.ametys.runtime.i18n.I18nizableText;
051import org.ametys.runtime.parameter.ParameterHelper;
052import org.ametys.runtime.parameter.ParameterHelper.ParameterType;
053
054import com.opensymphony.workflow.Workflow;
055import com.opensymphony.workflow.spi.Step;
056
057/**
058 * Generate all the needed calendar's informations
059 */
060public class CalendarEventInfoGenerator extends ServiceableGenerator
061{
062    /** The object resolver */
063    protected AmetysObjectResolver _resolver;
064    /** The ametys users manager */
065    protected UserManager _userManager;
066    /** The workflow provider */
067    protected WorkflowProvider _workflowProvider;
068    /** The workflow helper */
069    protected WorkflowHelper _workflowHelper;
070    
071    @Override
072    public void service(ServiceManager serviceManager) throws ServiceException
073    {
074        super.service(serviceManager);
075        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
076        _userManager = (UserManager) serviceManager.lookup(UserManager.ROLE);
077        _workflowProvider = (WorkflowProvider) serviceManager.lookup(WorkflowProvider.ROLE);
078        _workflowHelper = (WorkflowHelper) serviceManager.lookup(WorkflowHelper.ROLE);
079    }
080    
081    public void generate() throws IOException, SAXException, ProcessingException
082    {
083        Request request = ObjectModelHelper.getRequest(objectModel);
084        
085        String startDateString = request.getParameter("start");
086        Date startDate = (Date) ParameterHelper.castValue(startDateString, ParameterType.DATE);
087
088        String endDateString = request.getParameter("end");
089        Date endDate = (Date) ParameterHelper.castValue(endDateString, ParameterType.DATE);
090
091        String handleWorkflowInit = request.getParameter("handleWorkflowInit");
092
093        contentHandler.startDocument();
094        XMLUtils.startElement(contentHandler, "infos");
095        
096        String ids = request.getParameter("ids");
097        String occurrencesDate = request.getParameter("occurrencesDate");
098        
099        if (StringUtils.isNotBlank(ids) && StringUtils.isNotBlank(occurrencesDate))
100        {
101            String[] eventsIds = StringUtils.split(ids, ",");
102            String[] eventOccurrencesDate = StringUtils.split(occurrencesDate, ",");
103            
104            XMLUtils.startElement(contentHandler, "events");
105            for (int i = 0; i < eventsIds.length; i++)
106            {
107                String id = eventsIds[i];
108                String occurrenceDate = eventOccurrencesDate[i];
109                
110                long date = ZonedDateTime.parse(occurrenceDate, DateTimeFormatter.ISO_DATE_TIME).toInstant().toEpochMilli();
111                CalendarEvent event = _resolver.resolveById(id);
112                _saxEvent(event, new Date(date));
113            }
114            XMLUtils.endElement(contentHandler, "events");
115        }
116        else
117        {
118            String calendarId = request.getParameter("calendarId");
119            if (calendarId != null)
120            {
121                Calendar calendar = _resolver.resolveById(calendarId);
122                
123                if ("true".equals(request.getParameter("fromRootCalendar")))
124                {
125                    AmetysObject parent = calendar;
126                        
127                    while (parent instanceof Calendar)
128                    {
129                        calendar = (Calendar) parent;
130                        parent = parent.getParent();
131                    }
132                }
133                
134                _saxCalendar(calendar, "true".equals(request.getParameter("recursive")), "true".equals(request.getParameter("sax-events")), startDate, endDate, handleWorkflowInit);
135            }
136        }
137        
138        XMLUtils.endElement(contentHandler, "infos");  
139        contentHandler.endDocument();
140    }
141
142    private void _saxCalendar(Calendar calendar, boolean recursive, boolean saxEvents, Date startDate, Date endDate, String handleWorkflowInit) throws SAXException
143    {
144        AttributesImpl attr = new AttributesImpl();
145        attr.addCDATAAttribute("id", calendar.getId());
146        attr.addCDATAAttribute("title", calendar.getName());
147        attr.addCDATAAttribute("desc", calendar.getDescription());
148        attr.addCDATAAttribute("templateDesc", calendar.getTemplateDescription());
149        attr.addCDATAAttribute("color", calendar.getColor());
150        attr.addCDATAAttribute("workflowName", calendar.getWorkflowName());
151        attr.addCDATAAttribute("modifiable", calendar instanceof ModifiableAmetysObject ? "true" : "false");
152        attr.addCDATAAttribute("hasRight", "true");
153        attr.addCDATAAttribute("removable", calendar instanceof RemovableAmetysObject ? "true" : "false");
154        
155        HashMap<String, Object> inputs = new HashMap<>();
156        inputs.put(AbstractExplorerNodeWorkflowComponent.EXPLORERNODE_KEY, calendar);
157        if (handleWorkflowInit == null)
158        {
159            Workflow workflow = _workflowProvider.getAmetysObjectWorkflow();
160            attr.addCDATAAttribute("canInitWorkflow", workflow.canInitialize(calendar.getWorkflowName(), 1, inputs) ? "true" : "false");
161        }
162        else
163        {
164            attr.addCDATAAttribute("canInitWorkflow", "true");
165        }
166        XMLUtils.startElement(contentHandler, "calendar", attr);
167
168        if (recursive)
169        {
170            XMLUtils.startElement(contentHandler, "calendars");
171            for (AmetysObject object : calendar.getChildren())
172            {
173                if (object instanceof Calendar)
174                {
175                    Calendar subCalendar = (Calendar) object;
176                    _saxCalendar(subCalendar, recursive, saxEvents, startDate, endDate, handleWorkflowInit);
177                }
178            }
179            XMLUtils.endElement(contentHandler, "calendars");
180        }
181        
182        if (saxEvents)
183        {
184            XMLUtils.startElement(contentHandler, "events");
185            
186            for (Map.Entry<CalendarEvent, List<Date>> entry : calendar.getEvents(startDate, endDate).entrySet())
187            {
188                CalendarEvent event = entry.getKey();
189                List<Date> occurences = entry.getValue();
190                for (Date date : occurences)
191                {
192                    _saxEvent(event, date);
193                }
194            }
195            XMLUtils.endElement(contentHandler, "events");
196        }
197        
198        XMLUtils.endElement(contentHandler, "calendar");
199    }
200
201    private void _saxEvent(CalendarEvent event, Date date) throws SAXException
202    {
203        AttributesImpl attr = new AttributesImpl();
204        String id = event.getId() + "$" + ParameterHelper.valueToString(date);
205        attr.addCDATAAttribute("id", id);
206        attr.addCDATAAttribute("calendarId", event.getParent().getId());
207        attr.addCDATAAttribute("workflowId", event.getWorkflowId() + "");
208        attr.addCDATAAttribute("color", ((Calendar) event.getParent()).getColor());
209        attr.addCDATAAttribute("modifiable", "true");
210        
211        XMLUtils.startElement(contentHandler, "event", attr);
212        
213        Workflow workflow = _workflowProvider.getAmetysObjectWorkflow(event);
214        List<Step> listSteps = workflow.getCurrentSteps(event.getWorkflowId());
215        if (!listSteps.isEmpty())
216        {
217            // We select the first current step
218            Step step = listSteps.get(0);
219            String stepDesc = _workflowHelper.getStepName(((Calendar) event.getParent()).getWorkflowName(), step.getStepId());
220            I18nizableText workflowStepName = new I18nizableText("application", stepDesc);
221            
222            if ("application".equals(workflowStepName.getCatalogue()))
223            {
224                XMLUtils.createElement(contentHandler, "icon-small-workflow", "/plugins/explorer/resources_workflow/" + workflowStepName.getKey() + "-small.png");
225            }
226            else
227            {
228                String pluginName = workflowStepName.getCatalogue().substring("plugin.".length());
229                XMLUtils.createElement(contentHandler, "icon-small-workflow", "/plugins/" + pluginName + "/resources/img/workflow/" + workflowStepName.getKey() + "-small.png");
230            }
231        }
232        
233        XMLUtils.createElement(contentHandler, "title", event.getTitle());
234        XMLUtils.createElement(contentHandler, "desc", event.getDescription());
235        XMLUtils.createElement(contentHandler, "fullDay", event.getFullDay() ? "true" : "false");
236        
237        XMLUtils.createElement(contentHandler, "recurrenceType", event.getRecurrenceType().toString());
238        
239        String untilDateAsString = "";
240        Date untilDate = event.getRepeatUntil();
241        if (untilDate != null)
242        {
243            untilDateAsString =  ParameterHelper.valueToString(untilDate);
244        }
245        XMLUtils.createElement(contentHandler, "untilDate", untilDateAsString);
246        
247        Date firstStartDateEvent = event.getStartDate();
248        Date firstEndDateEvent = event.getEndDate();
249        
250        long diff = firstEndDateEvent.getTime() - firstStartDateEvent.getTime();
251        Date startDateEvent = date;
252        Date endDateEvent = new Date(date.getTime() + diff);
253        
254        if (event.getFullDay())
255        {
256            GregorianCalendar gcStart = new GregorianCalendar();
257            gcStart.setTime(startDateEvent);
258            gcStart.set(java.util.Calendar.HOUR_OF_DAY, 0);
259            gcStart.set(java.util.Calendar.MINUTE, 0);
260            gcStart.set(java.util.Calendar.SECOND, 0);
261            gcStart.set(java.util.Calendar.MILLISECOND, 0);
262     
263            startDateEvent = gcStart.getTime();
264            
265            GregorianCalendar gcEnd = new GregorianCalendar();
266            gcEnd.setTime(endDateEvent);
267            gcEnd.set(java.util.Calendar.HOUR_OF_DAY, 23);
268            gcEnd.set(java.util.Calendar.MINUTE, 59);
269            gcEnd.set(java.util.Calendar.SECOND, 59);
270            gcEnd.set(java.util.Calendar.MILLISECOND, 999);
271     
272            endDateEvent = gcEnd.getTime();
273        }
274        
275        XMLUtils.createElement(contentHandler, "startDate", ParameterHelper.valueToString(startDateEvent));
276        XMLUtils.createElement(contentHandler, "endDate", ParameterHelper.valueToString(endDateEvent));
277        _saxUser(event.getCreator(), "creator");
278        XMLUtils.createElement(contentHandler, "creationDate", ParameterHelper.valueToString(event.getCreationDate()));
279        _saxUser(event.getLastContributor(), "contributor");
280        XMLUtils.createElement(contentHandler, "lastModified", ParameterHelper.valueToString(event.getLastModified()));
281        
282        UserIdentity validator = event.getLastValidator();
283        if (validator != null)
284        {
285            _saxUser(validator, "validator");
286        }
287        
288        Date lastValidated = event.getLastValidated();
289        if (lastValidated != null)
290        {
291            XMLUtils.createElement(contentHandler, "lastValidated", ParameterHelper.valueToString(lastValidated));
292        }
293        
294        XMLUtils.endElement(contentHandler, "event");
295    }
296    
297    private void _saxUser(UserIdentity userIdentity, String tagName) throws SAXException
298    {
299        AttributesImpl attr = new AttributesImpl();
300        attr.addCDATAAttribute("login", userIdentity.getLogin());
301        attr.addCDATAAttribute("population", userIdentity.getPopulationId());
302        
303        User user = _userManager.getUser(userIdentity.getPopulationId(), userIdentity.getLogin());
304        if (user != null)
305        {
306            attr.addCDATAAttribute("fullName", user.getFullName());
307        }
308        
309        XMLUtils.createElement(contentHandler, tagName, attr);
310    }
311}