View Javadoc
1   /*
2    * Copyright (c) 2002-2014, Mairie de Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.plugins.calendar.service;
35  
36  import fr.paris.lutece.plugins.calendar.business.Agenda;
37  import fr.paris.lutece.plugins.calendar.business.CalendarFilter;
38  import fr.paris.lutece.plugins.calendar.business.CalendarHome;
39  import fr.paris.lutece.plugins.calendar.business.Event;
40  import fr.paris.lutece.plugins.calendar.business.SimpleEvent;
41  import fr.paris.lutece.plugins.calendar.business.category.Category;
42  import fr.paris.lutece.plugins.calendar.service.search.CalendarSearchService;
43  import fr.paris.lutece.plugins.calendar.web.Constants;
44  import fr.paris.lutece.portal.service.content.XPageAppService;
45  import fr.paris.lutece.portal.service.i18n.I18nService;
46  import fr.paris.lutece.portal.service.plugin.Plugin;
47  import fr.paris.lutece.portal.service.plugin.PluginService;
48  import fr.paris.lutece.portal.service.util.AppLogService;
49  import fr.paris.lutece.portal.service.util.AppPathService;
50  import fr.paris.lutece.portal.service.util.AppPropertiesService;
51  import fr.paris.lutece.util.date.DateUtil;
52  import fr.paris.lutece.util.url.UrlItem;
53  import fr.paris.lutece.util.xml.XmlUtil;
54  
55  import java.io.ByteArrayOutputStream;
56  import java.io.InputStream;
57  import java.io.StringReader;
58  import java.text.SimpleDateFormat;
59  import java.util.Calendar;
60  import java.util.Collection;
61  import java.util.Date;
62  import java.util.GregorianCalendar;
63  import java.util.Iterator;
64  import java.util.List;
65  import java.util.Locale;
66  import java.util.Map;
67  import java.util.Map.Entry;
68  import java.util.Properties;
69  import java.util.Set;
70  
71  import javax.servlet.http.HttpServletRequest;
72  import javax.xml.transform.Result;
73  import javax.xml.transform.Source;
74  import javax.xml.transform.Transformer;
75  import javax.xml.transform.TransformerConfigurationException;
76  import javax.xml.transform.TransformerException;
77  import javax.xml.transform.TransformerFactory;
78  import javax.xml.transform.TransformerFactoryConfigurationError;
79  import javax.xml.transform.stream.StreamResult;
80  import javax.xml.transform.stream.StreamSource;
81  
82  import org.apache.commons.lang.StringUtils;
83  
84  
85  /**
86   * This class provides utils features to manipulate and convert XML calendar
87   * information
88   */
89  public final class XMLUtils
90  {
91      // CSS Styles
92      public static final String STYLE_CLASS_VIEW_MONTH_DAY = "calendar-view-month-day";
93      public static final String STYLE_CLASS_VIEW_WEEK_DAY = "calendar-view-week-day";
94      public static final String STYLE_CLASS_SMALLMONTH_DAY = "calendar-smallmonth-day";
95      public static final String STYLE_CLASS_SUFFIX_OLD = "-old";
96      public static final String STYLE_CLASS_SUFFIX_TODAY = "-today";
97      public static final String STYLE_CLASS_SUFFIX_OFF = "-off";
98      public static final String STYLE_CLASS_EMPTY_DAY = "calendar-smallmonth-day";
99  
100     // The names of the XML tags    
101     private static final String TAG_EVENTS = "events";
102     private static final String TAG_AGENDA_EVENT = "event";
103     private static final String TAG_AGENDA_EVENT_DATE = "event-date";
104     private static final String TAG_AGENDA_EVENT_LOCATION = "event-location";
105     private static final String TAG_AGENDA_EVENT_DESCRIPTION = "event-description";
106     private static final String TAG_AGENDA_EVENT_DATE_TIME_START = "event-date-time-start";
107     private static final String TAG_AGENDA_EVENT_DATE_TIME_END = "event-date-time-end";
108     private static final String TAG_AGENDA_EVENT_CATEGORIES = "event-categories";
109     private static final String TAG_AGENDA_EVENT_STATUS = "event-status";
110     private static final String TAG_AGENDA_EVENT_SUMMARY = "event-summary";
111     private static final String TAG_AGENDA_EVENT_URL = "event-url";
112     private static final String TAG_AGENDA_EVENT_DATE_CREATION = "event-creation-date";
113 
114     /* Since version 3.0.0 */
115     private static final String TAG_AGENDA_MONTH = "month";
116     private static final String TAG_AGENDA_MONTH_LABEL = "month-label";
117     private static final String TAG_AGENDA_WEEKS = "weeks";
118     private static final String TAG_AGENDA_WEEK = "week";
119     private static final String TAG_AGENDA_DAY = "day";
120     private static final String TAG_AGENDA_DAY_CODE = "day-code";
121     private static final String TAG_AGENDA_DAY_LABEL = "day-label";
122     private static final String TAG_WEEK_SHORTCUTS = "week-shortcuts";
123     private static final String TAG_WEEK_SHORTCUT = "week-shortcut";
124     private static final String TAG_WEEK_SHORTCUT_LABEL = "week-shortcut-label";
125     private static final String TAG_WEEK_SHORTCUT_PERIOD = "week-shortcut-period";
126     private static final String TAG_WEEK_SHORTCUT_DATE_START = "week-shortcut-date-start";
127     private static final String TAG_WEEK_SHORTCUT_DATE_END = "week-shortcut-date-end";
128 
129     //PROPERTIES
130     private static final String PROPERTY_SPACE = " ";
131     private static final String PROPERTY_COMMA = ",";
132     private static final String PROPERTY_CALENDAR_RSS_PATTERN = "calendar.rss.format.date";
133     private static final String PROPERTY_EMPTY_DAY = " ";
134 
135     //Html components
136     private static final String BEGIN_TD_TAG = "<td class=";
137     private static final String END_TD_TAG = "</td>";
138     private static final String BEGIN_A_TAG = "<a href=\"";
139     private static final String END_A_TAG = "</a>";
140     private static final String BEGIN_BOLD_TAG = "<b>";
141     private static final String END_BOLD_TAG = "</b>";
142 
143     //LOGGER    
144     private static final String LOGGER_CALENDAR_EXPORT_XML_CONTENT = "lutece.debug.calendar.export.xmlContent";
145 
146     /**
147      * Default constructor
148      */
149     private XMLUtils( )
150     {
151     }
152 
153     /**
154      * Returns the Xml code of a calendar events
155      * 
156      * @param strAgenda The id of the agenda
157      * @param request request servlet request
158      * @return the Xml code of the agenda content
159      */
160     public static String getAgendaXml( String strAgenda, HttpServletRequest request )
161     {
162         Agenda agenda = Utils.getAgendaWithOccurrences( strAgenda, request );
163         List<Event> listEvents = agenda.getEvents( );
164 
165         return getXml( listEvents );
166     }
167 
168     /**
169      * Returns the Xml code for RSS
170      * 
171      * @param filter The filter
172      * @return the Xml code of the agenda content
173      */
174     public static String getRssXml( CalendarFilter filter )
175     {
176         List<Event> listEvents = CalendarHome.findEventsByFilter( filter,
177                 PluginService.getPlugin( Constants.PLUGIN_NAME ) );
178 
179         return getXml( listEvents );
180     }
181 
182     /**
183      * Returns the Xml code of the Calendar portlet without XML heading
184      * 
185      * @param listEvents The list of events
186      * @return the Xml code of the agenda content
187      */
188     public static String getXml( List<Event> listEvents )
189     {
190         if ( listEvents != null )
191         {
192             StringBuffer strXml = new StringBuffer( );
193             strXml.append( XmlUtil.getXmlHeader( ) );
194 
195             // Generate the XML code for the agendas :
196             XmlUtil.beginElement( strXml, TAG_EVENTS );
197 
198             Iterator<Event> i = listEvents.iterator( );
199 
200             while ( i.hasNext( ) )
201             {
202                 SimpleEvent event = (SimpleEvent) i.next( );
203 
204                 XmlUtil.beginElement( strXml, TAG_AGENDA_EVENT );
205                 XmlUtil.addElement( strXml, TAG_AGENDA_EVENT_SUMMARY, ( event.getTitle( ) != null ) ? event.getTitle( )
206                         : "" );
207 
208                 String strAddress = event.getLocationAddress( );
209                 String strTown = event.getLocationTown( );
210                 String strZip = event.getLocationZip( );
211 
212                 String strLocation = event.getLocation( );
213 
214                 if ( strAddress != null )
215                 {
216                     strLocation += ( PROPERTY_SPACE + strAddress );
217                 }
218 
219                 if ( strZip != null )
220                 {
221                     strLocation += ( PROPERTY_SPACE + strZip );
222                 }
223 
224                 if ( strTown != null )
225                 {
226                     strLocation += ( PROPERTY_SPACE + strTown );
227                 }
228 
229                 UrlItem urlEvent = new UrlItem( AppPathService.getPortalUrl( ) );
230                 urlEvent.addParameter( XPageAppService.PARAM_XPAGE_APP, CalendarPlugin.PLUGIN_NAME );
231                 urlEvent.addParameter( Constants.PARAMETER_ACTION, Constants.ACTION_SHOW_RESULT );
232                 urlEvent.addParameter( Constants.PARAMETER_EVENT_ID, event.getId( ) );
233                 urlEvent.addParameter( Constants.PARAM_AGENDA, event.getIdCalendar( ) );
234 
235                 String strCreationdate = Constants.EMPTY_STRING;
236 
237                 if ( event.getDateCreation( ) != null )
238                 {
239                     SimpleDateFormat sdf = new SimpleDateFormat(
240                             AppPropertiesService.getProperty( PROPERTY_CALENDAR_RSS_PATTERN ), Locale.US );
241                     strCreationdate = sdf.format( event.getDateCreation( ) );
242                 }
243 
244                 XmlUtil.addElement( strXml, TAG_AGENDA_EVENT_LOCATION, ( strLocation != null ) ? strLocation : "" );
245                 XmlUtil.addElement( strXml, TAG_AGENDA_EVENT_DESCRIPTION,
246                         ( event.getDescription( ) != null ) ? event.getDescription( ) : "" );
247 
248                 if ( event.getListCategories( ) != null )
249                 {
250                     Collection<Category> listCategories = event.getListCategories( );
251                     String strCategories = PROPERTY_SPACE;
252 
253                     for ( Category category : listCategories )
254                     {
255                         if ( strCategories.equals( PROPERTY_SPACE ) )
256                         {
257                             strCategories = category.getName( );
258                         }
259                         else
260                         {
261                             strCategories += ( strCategories + PROPERTY_COMMA + category.getName( ) );
262                         }
263                     }
264 
265                     XmlUtil.addElement( strXml, TAG_AGENDA_EVENT_CATEGORIES, strCategories.trim( ) );
266                 }
267 
268                 XmlUtil.addElement( strXml, TAG_AGENDA_EVENT_STATUS, ( event.getStatus( ) != null ) ? event.getStatus( )
269                         : "" );
270                 XmlUtil.addElement( strXml, TAG_AGENDA_EVENT_DATE_TIME_START,
271                         ( event.getDateTimeStart( ) != null ) ? event.getDateTimeStart( ).replace( ":", "" ) : "" );
272                 XmlUtil.addElement( strXml, TAG_AGENDA_EVENT_DATE_TIME_END, ( event.getDateTimeEnd( ) != null ) ? event
273                         .getDateTimeEnd( ).replace( ":", "" ) : "" );
274                 XmlUtil.addElement( strXml, TAG_AGENDA_EVENT_DATE, Utils.getDate( event.getDate( ) ) );
275                 XmlUtil.addElementHtml( strXml, TAG_AGENDA_EVENT_URL, urlEvent.getUrl( ) );
276                 XmlUtil.addElement( strXml, TAG_AGENDA_EVENT_DATE_CREATION, strCreationdate );
277 
278                 XmlUtil.endElement( strXml, TAG_AGENDA_EVENT );
279             }
280 
281             XmlUtil.endElement( strXml, TAG_EVENTS );
282 
283             if ( AppLogService.isDebugEnabled( LOGGER_CALENDAR_EXPORT_XML_CONTENT ) )
284             {
285                 AppLogService.debug( LOGGER_CALENDAR_EXPORT_XML_CONTENT, strXml.toString( ) );
286             }
287 
288             return strXml.toString( );
289         }
290         return Constants.EMPTY_STRING;
291     }
292 
293     /**
294      * This method performs XSL Transformation.
295      * 
296      * @param strXml The input XML document
297      * @param baSource The source input stream
298      * @param params parameters to apply to the XSL Stylesheet
299      * @param outputProperties properties to use for the xsl transform. Will
300      *            overload the xsl output definition.
301      * @return The output document transformed
302      * @throws Exception The exception
303      */
304     public static byte[] transformXMLToXSL( String strXml, InputStream baSource, Map<String, String> params,
305             Properties outputProperties ) throws Exception
306     {
307         Source stylesheet = new StreamSource( baSource );
308         StringReader srInputXml = new StringReader( strXml );
309         StreamSource source = new StreamSource( srInputXml );
310 
311         try
312         {
313             TransformerFactory factory = TransformerFactory.newInstance( );
314             Transformer transformer = factory.newTransformer( stylesheet );
315 
316             if ( outputProperties != null )
317             {
318                 transformer.setOutputProperties( outputProperties );
319             }
320 
321             if ( params != null )
322             {
323                 transformer.clearParameters( );
324 
325                 Set<Entry<String, String>> entries = params.entrySet( );
326 
327                 for ( Entry<String, String> entry : entries )
328                 {
329                     String name = entry.getKey( );
330                     String value = entry.getValue( );
331                     transformer.setParameter( name, value );
332                 }
333             }
334 
335             ByteArrayOutputStream out = new ByteArrayOutputStream( );
336             Result result = new StreamResult( out );
337             transformer.transform( source, result );
338 
339             return out.toByteArray( );
340         }
341         catch ( TransformerConfigurationException e )
342         {
343             String strMessage = e.getMessage( );
344 
345             if ( e.getLocationAsString( ) != null )
346             {
347                 strMessage += ( "- location : " + e.getLocationAsString( ) );
348             }
349 
350             throw new Exception( "Error transforming document XSLT : " + strMessage, e.getCause( ) );
351         }
352         catch ( TransformerFactoryConfigurationError e )
353         {
354             throw new Exception( "Error transforming document XSLT : " + e.getMessage( ), e );
355         }
356         catch ( TransformerException e )
357         {
358             String strMessage = e.getMessage( );
359 
360             if ( e.getLocationAsString( ) != null )
361             {
362                 strMessage += ( "- location : " + e.getLocationAsString( ) );
363             }
364 
365             throw new Exception( "Error transforming document XSLT : " + strMessage, e.getCause( ) );
366         }
367         catch ( Exception e )
368         {
369             throw new Exception( "Error transforming document XSLT : " + e.getMessage( ), e );
370         }
371     }
372 
373     /**
374      * Get the XML of a calendar
375      * @param local The locale
376      * @param cal The calendar
377      * @param request The request
378      * @return The XML
379      */
380     public static String getXMLPortletCalendar( Locale local, Calendar cal, HttpServletRequest request )
381     {
382         StringBuffer strXml = new StringBuffer( );
383 
384         String strDay = null;
385         Calendar calendar = new GregorianCalendar( );
386 
387         //Set the calendar in the beginning of the month
388         calendar.set( cal.get( Calendar.YEAR ), cal.get( Calendar.MONTH ), 1 );
389 
390         int nDayOfWeek = calendar.get( Calendar.DAY_OF_WEEK );
391 
392         //If day of week is sunday: nDayOfWeek = 8
393         if ( nDayOfWeek == 1 )
394         {
395             nDayOfWeek = 8;
396         }
397 
398         Calendar calendar2 = new GregorianCalendar( );
399         calendar2
400                 .set( cal.get( Calendar.YEAR ), cal.get( Calendar.MONTH ), calendar.getMaximum( Calendar.DAY_OF_MONTH ) );
401 
402         //Beginning of the main xml block: month
403         XmlUtil.beginElement( strXml, TAG_AGENDA_MONTH );
404 
405         String strBaseUrl = AppPathService.getPortalUrl( );
406 
407         UrlItem urlMonth = new UrlItem( strBaseUrl );
408         urlMonth.addParameter( Constants.PARAMETER_PAGE, Constants.PLUGIN_NAME );
409         urlMonth.addParameter( Constants.PARAMETER_ACTION, Constants.ACTION_DO_SEARCH );
410 
411         urlMonth.addParameter( Constants.PARAMETER_DATE_START, DateUtil.getDateString( calendar.getTime( ), local ) );
412         urlMonth.addParameter( Constants.PARAMETER_DATE_END, DateUtil.getDateString( calendar2.getTime( ), local ) );
413         urlMonth.addParameter( Constants.PARAMETER_PERIOD, Constants.PROPERTY_PERIOD_RANGE );
414 
415         String strMonthLabel = Utils.getMonthLabel( Utils.getDate( calendar ), local );
416 
417         String strUrlMonth = BEGIN_A_TAG + urlMonth.getUrl( ) + "\">" + strMonthLabel + END_A_TAG;
418 
419         XmlUtil.addElementHtml( strXml, TAG_AGENDA_MONTH_LABEL, strUrlMonth );
420 
421         //Shortcut tags
422         //Begenning of the xml block: week-shortcuts
423         XmlUtil.beginElement( strXml, TAG_WEEK_SHORTCUTS );
424 
425         //Today shortcut 
426         XmlUtil.beginElement( strXml, TAG_WEEK_SHORTCUT );
427         XmlUtil.addElement( strXml, TAG_WEEK_SHORTCUT_LABEL,
428                 I18nService.getLocalizedString( Constants.PROPERTY_SHORTCUT_TODAY, local ) );
429         XmlUtil.addElement( strXml, TAG_WEEK_SHORTCUT_PERIOD, Constants.PROPERTY_PERIOD_TODAY );
430         XmlUtil.addElement( strXml, TAG_WEEK_SHORTCUT_DATE_START, DateUtil.getDateString( new Date( ), local ) );
431         XmlUtil.addElement( strXml, TAG_WEEK_SHORTCUT_DATE_END, DateUtil.getDateString( new Date( ), local ) );
432         XmlUtil.endElement( strXml, TAG_WEEK_SHORTCUT );
433 
434         //Tomorrow shortcut 
435         Calendar calTomorrow = new GregorianCalendar( );
436         calTomorrow.add( Calendar.DATE, 1 );
437         XmlUtil.beginElement( strXml, TAG_WEEK_SHORTCUT );
438         XmlUtil.addElement( strXml, TAG_WEEK_SHORTCUT_LABEL,
439                 I18nService.getLocalizedString( Constants.PROPERTY_SHORTCUT_TOMORROW, local ) );
440         XmlUtil.addElement( strXml, TAG_WEEK_SHORTCUT_PERIOD, Constants.PROPERTY_PERIOD_RANGE );
441         XmlUtil.addElement( strXml, TAG_WEEK_SHORTCUT_DATE_START,
442                 DateUtil.getDateString( calTomorrow.getTime( ), local ) );
443         XmlUtil.addElement( strXml, TAG_WEEK_SHORTCUT_DATE_END, DateUtil.getDateString( calTomorrow.getTime( ), local ) );
444         XmlUtil.endElement( strXml, TAG_WEEK_SHORTCUT );
445 
446         //Week shortcut
447         Date dateBeginWeek = null;
448         Date dateEndWeek = null;
449 
450         Calendar calendarToday = new GregorianCalendar( );
451         Calendar calendarFirstDay = Calendar.getInstance( );
452         Calendar calendarLastDay = new GregorianCalendar( );
453 
454         calendarFirstDay = calendarToday;
455         calendarFirstDay.set( Calendar.DAY_OF_WEEK, Calendar.MONDAY );
456         calendarLastDay = (GregorianCalendar) calendarFirstDay.clone( );
457         calendarLastDay.add( Calendar.DATE, 6 );
458         dateBeginWeek = calendarFirstDay.getTime( );
459         dateEndWeek = calendarLastDay.getTime( );
460 
461         XmlUtil.beginElement( strXml, TAG_WEEK_SHORTCUT );
462         XmlUtil.addElement( strXml, TAG_WEEK_SHORTCUT_LABEL,
463                 I18nService.getLocalizedString( Constants.PROPERTY_SHORTCUT_WEEK, local ) );
464         XmlUtil.addElement( strXml, TAG_WEEK_SHORTCUT_PERIOD, Constants.PROPERTY_PERIOD_WEEK );
465         XmlUtil.addElement( strXml, TAG_WEEK_SHORTCUT_DATE_START, DateUtil.getDateString( dateBeginWeek, local ) );
466         XmlUtil.addElement( strXml, TAG_WEEK_SHORTCUT_DATE_END, DateUtil.getDateString( dateEndWeek, local ) );
467         XmlUtil.endElement( strXml, TAG_WEEK_SHORTCUT );
468 
469         //Ending of the xml block: week-shortcuts
470         XmlUtil.endElement( strXml, TAG_WEEK_SHORTCUTS );
471 
472         //Begenning of the xml block: weeks
473         XmlUtil.beginElement( strXml, TAG_AGENDA_WEEKS );
474 
475         //Day label tags
476         XmlUtil.addElement( strXml, TAG_AGENDA_DAY_LABEL,
477                 I18nService.getLocalizedString( Constants.PROPERTY_SHORTLABEL_MONDAY, local ) );
478         XmlUtil.addElement( strXml, TAG_AGENDA_DAY_LABEL,
479                 I18nService.getLocalizedString( Constants.PROPERTY_SHORTLABEL_TUESDAY, local ) );
480         XmlUtil.addElement( strXml, TAG_AGENDA_DAY_LABEL,
481                 I18nService.getLocalizedString( Constants.PROPERTY_SHORTLABEL_WEDNESDAY, local ) );
482         XmlUtil.addElement( strXml, TAG_AGENDA_DAY_LABEL,
483                 I18nService.getLocalizedString( Constants.PROPERTY_SHORTLABEL_THURSDAY, local ) );
484         XmlUtil.addElement( strXml, TAG_AGENDA_DAY_LABEL,
485                 I18nService.getLocalizedString( Constants.PROPERTY_SHORTLABEL_FRIDAY, local ) );
486         XmlUtil.addElement( strXml, TAG_AGENDA_DAY_LABEL,
487                 I18nService.getLocalizedString( Constants.PROPERTY_SHORTLABEL_SATURDAY, local ) );
488         XmlUtil.addElement( strXml, TAG_AGENDA_DAY_LABEL,
489                 I18nService.getLocalizedString( Constants.PROPERTY_SHORTLABEL_SUNDAY, local ) );
490 
491         //Check if the month is ended
492         boolean bDone = false;
493 
494         //check if the month is started
495         boolean bStarted = false;
496 
497         //While the month isn't over...
498         while ( !bDone )
499         {
500             //Begenning of the xml block: week
501             XmlUtil.beginElement( strXml, TAG_AGENDA_WEEK );
502 
503             for ( int i = 0; i < 7; i++ )
504             {
505                 if ( ( ( ( i + 2 ) != nDayOfWeek ) && !bStarted ) || bDone )
506                 {
507                     XmlUtil.beginElement( strXml, TAG_AGENDA_DAY );
508                     strDay = BEGIN_TD_TAG + getDayClass( calendar ) + ">" + PROPERTY_EMPTY_DAY + END_TD_TAG;
509                     XmlUtil.addElementHtml( strXml, TAG_AGENDA_DAY_CODE, strDay );
510                     XmlUtil.endElement( strXml, TAG_AGENDA_DAY );
511 
512                     continue;
513                 }
514                 bStarted = true;
515 
516                 //put parameters in the url
517                 UrlItem urlDay = new UrlItem( strBaseUrl );
518                 String strPageId = request != null ? request.getParameter( Constants.PARAMETER_PAGE_ID )
519                         : StringUtils.EMPTY;
520                 if ( StringUtils.isNotBlank( strPageId ) && StringUtils.isNumeric( strPageId ) )
521                 {
522                     urlDay.addParameter( Constants.PARAMETER_PAGE_ID, strPageId );
523                 }
524                 urlDay.addParameter( Constants.PARAMETER_DATE, DateUtil.getDateString( calendar.getTime( ), local ) );
525 
526                 //construct on url based on day
527                 String strUrlDay = new String( );
528                 strUrlDay = BEGIN_A_TAG + urlDay.getUrl( ) + "\">"
529                         + Integer.toString( calendar.get( Calendar.DAY_OF_MONTH ) ) + END_A_TAG;
530 
531                 XmlUtil.beginElement( strXml, TAG_AGENDA_DAY );
532 
533                 Date date = Utils.getDate( Utils.getDate( calendar ) );
534                 Plugin plugin = PluginService.getPlugin( CalendarPlugin.PLUGIN_NAME );
535 
536                 String[] arrayCalendarIds = Utils.getCalendarIds( request );
537 
538                 List<Event> listEvent = CalendarSearchService.getInstance( ).getSearchResults( arrayCalendarIds, null,
539                         "", date, date, plugin );
540                 if ( listEvent.size( ) != 0 )
541                 {
542                     strDay = BEGIN_TD_TAG + Constants.STYLE_CLASS_SMALLMONTH_DAY + Constants.STYLE_CLASS_SUFFIX_EVENT
543                             + ">" + BEGIN_BOLD_TAG + strUrlDay + END_BOLD_TAG + END_TD_TAG;
544                 }
545                 else
546                 {
547                     strDay = BEGIN_TD_TAG + getDayClass( calendar ) + ">"
548                             + Integer.toString( calendar.get( Calendar.DAY_OF_MONTH ) ) + END_TD_TAG;
549                 }
550 
551                 XmlUtil.addElementHtml( strXml, TAG_AGENDA_DAY_CODE, strDay );
552 
553                 XmlUtil.endElement( strXml, TAG_AGENDA_DAY );
554 
555                 int nDay = calendar.get( Calendar.DAY_OF_MONTH );
556                 calendar.roll( Calendar.DAY_OF_MONTH, true );
557 
558                 int nNewDay = calendar.get( Calendar.DAY_OF_MONTH );
559 
560                 if ( nNewDay < nDay )
561                 {
562                     bDone = true;
563                 }
564             }
565 
566             //Ending of the xml block: week
567             XmlUtil.endElement( strXml, TAG_AGENDA_WEEK );
568         }
569 
570         //Ending of the xml block: weeks
571         XmlUtil.endElement( strXml, TAG_AGENDA_WEEKS );
572 
573         //Ending of the xml block: month
574         XmlUtil.endElement( strXml, TAG_AGENDA_MONTH );
575 
576         return strXml.toString( );
577     }
578 
579     /**
580      * Calculate the style class to render the day
581      * @param calendar A calendar object positionned on the day to render
582      * @return A CSS style
583      */
584     private static String getDayClass( Calendar calendar )
585     {
586         StringBuilder sbClass = new StringBuilder( Constants.STYLE_CLASS_SMALLMONTH_DAY );
587         String strDate = Utils.getDate( calendar );
588         String strToday = Utils.getDateToday( );
589 
590         if ( Utils.isDayOff( calendar ) )
591         {
592             sbClass.append( Constants.STYLE_CLASS_SUFFIX_OFF );
593         }
594         else if ( strDate.compareTo( strToday ) < 0 )
595         {
596             sbClass.append( Constants.STYLE_CLASS_SUFFIX_OLD );
597         }
598         else if ( strDate.equals( strToday ) )
599         {
600             sbClass.append( Constants.STYLE_CLASS_SUFFIX_TODAY );
601         }
602 
603         return sbClass.toString( );
604     }
605 }