KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > generation > CalendarGenerator


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.generation;
17
18 import java.io.IOException JavaDoc;
19 import java.io.Serializable JavaDoc;
20 import java.text.DateFormat JavaDoc;
21 import java.text.DecimalFormat JavaDoc;
22 import java.text.SimpleDateFormat JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Calendar JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Locale JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.TimeZone JavaDoc;
29
30 import org.apache.avalon.framework.parameters.Parameters;
31 import org.apache.cocoon.ProcessingException;
32 import org.apache.cocoon.caching.CacheableProcessingComponent;
33 import org.apache.cocoon.environment.SourceResolver;
34 import org.apache.commons.lang.BooleanUtils;
35 import org.apache.excalibur.source.SourceValidity;
36 import org.apache.excalibur.source.impl.validity.NOPValidity;
37 import org.xml.sax.SAXException JavaDoc;
38 import org.xml.sax.helpers.AttributesImpl JavaDoc;
39
40 /**
41  * @cocoon.sitemap.component.documentation
42  * Generates an XML document representing a calendar for a given month and year.
43  *
44  * @cocoon.sitemap.component.documentation.caching TBD
45  * @cocoon.sitemap.component.name calendar
46  * @cocoon.sitemap.component.label content
47  * @cocoon.sitemap.component.logger sitemap.generator.calendar
48  *
49  *
50  * <p>
51  * Here is a sample output:
52  * </p>
53  * <pre>
54  * &lt;calendar:calendar xmlns:calendar="http://apache.org/cocoon/calendar/1.0"
55  * year="2004" month="January" prevMonth="12" prevYear="2003"
56  * nextMonth="02" nextYear="2004"&gt;
57  * &lt;calendar:week number="1"&gt;
58  * &lt;calendar:day number="1" weekday="THURSDAY" date="January 1, 2004"/&gt;
59  * &lt;calendar:day number="2" weekday="FRIDAY" date="January 2, 2004"/&gt;
60  * &lt;calendar:day number="3" weekday="SATURDAY" date="January 3, 2004"/&gt;
61  * &lt;calendar:day number="4" weekday="SUNDAY" date="January 4, 2004"/&gt;
62  * &lt;/calendar:week&gt;
63  * ...
64  * &lt;/calendar:calendar&gt;
65  * </pre>
66  * <p>
67  * The <i>src</i> parameter is ignored.
68  * </p>
69  * <p>
70  * <b>Configuration options:</b>
71  * <dl>
72  * <dt> <i>month</i> (optional)</dt>
73  * <dd> Sets the month for the calendar (January is 1). Default is the current month.</dd>
74  * <dt> <i>year</i> (optional)</dt>
75  * <dd> Sets the year for the calendar. Default is the current year.</dd>
76  * <dt> <i>dateFormat</i> (optional)</dt>
77  * <dd> Sets the format for the date attribute of each node, as
78  * described in java.text.SimpleDateFormat. If unset, the default
79  * format for the current locale will be used.</dd>
80  * <dt> <i>lang</i> (optional)</dt>
81  * <dd> Sets the ISO language code for determining the locale.</dd>
82  * <dt> <i>country</i> (optional)</dt>
83  * <dd> Sets the ISO country code for determining the locale.</dd>
84  * <dt> <i>padWeeks</i> (optional)</dt>
85  * <dd> If set to true, full weeks will be generated by adding
86  * days from the end of the previous month and the beginning
87  * of the following month.</dd>
88  * </dl>
89  * </p>
90  *
91  * @version CVS $Id: CalendarGenerator.java 330550 2005-11-03 14:00:55Z ugo $
92  */

93 public class CalendarGenerator extends ServiceableGenerator implements CacheableProcessingComponent {
94     
95     /** The URI of the namespace of this generator. */
96     protected static final String JavaDoc URI = "http://apache.org/cocoon/calendar/1.0";
97     
98     /** The namespace prefix for this namespace. */
99     protected static final String JavaDoc PREFIX = "calendar";
100     
101     /** Node and attribute names */
102     protected static final String JavaDoc CALENDAR_NODE_NAME = "calendar";
103     protected static final String JavaDoc WEEK_NODE_NAME = "week";
104     protected static final String JavaDoc DAY_NODE_NAME = "day";
105     protected static final String JavaDoc MONTH_ATTR_NAME = "month";
106     protected static final String JavaDoc YEAR_ATTR_NAME = "year";
107     protected static final String JavaDoc DATE_ATTR_NAME = "date";
108     protected static final String JavaDoc NUMBER_ATTR_NAME = "number";
109     protected static final String JavaDoc WEEKDAY_ATTR_NAME = "weekday";
110     protected static final String JavaDoc PREV_MONTH_ATTR_NAME = "prevMonth";
111     protected static final String JavaDoc PREV_YEAR_ATTR_NAME = "prevYear";
112     protected static final String JavaDoc NEXT_MONTH_ATTR_NAME = "nextMonth";
113     protected static final String JavaDoc NEXT_YEAR_ATTR_NAME = "nextYear";
114     
115     /** Formatter for month number */
116     protected static final DecimalFormat JavaDoc monthNumberFormatter = new DecimalFormat JavaDoc("00");
117     
118     /** Convenience object, so we don't need to create an AttributesImpl for every element. */
119     protected AttributesImpl JavaDoc attributes;
120     
121     /**
122      * The cache key needs to be generated for the configuration of this
123      * generator, so storing the parameters for generateKey().
124      */

125     protected List JavaDoc cacheKeyParList;
126     
127     /** The year to generate the calendar for */
128     protected int year;
129     
130     /** The month to generate the calendar for */
131     protected int month;
132     
133     /** The format for dates */
134     protected DateFormat JavaDoc dateFormatter;
135     
136     /** The format for month names */
137     protected DateFormat JavaDoc monthFormatter;
138     
139     /** The current locale */
140     protected Locale JavaDoc locale;
141     
142     /** Do we need to pad out the first and last weeks? */
143     protected boolean padWeeks;
144     
145     /* Add the day of the week
146      *
147      * since SUNDAY=1, we start with a dummy
148      * entry.
149      */

150     protected String JavaDoc weekdays[] = { "",
151         "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY",
152         "FRIDAY", "SATURDAY"
153     };
154     
155     /**
156      * Set the request parameters. Must be called before the generate method.
157      *
158      * @param resolver the SourceResolver object
159      * @param objectModel a <code>Map</code> containing model object
160      * @param src the source URI (ignored)
161      * @param par configuration parameters
162      */

163     public void setup(SourceResolver resolver, Map JavaDoc objectModel, String JavaDoc src, Parameters par)
164     throws ProcessingException, SAXException JavaDoc, IOException JavaDoc {
165         super.setup(resolver, objectModel, src, par);
166         
167         this.cacheKeyParList = new ArrayList JavaDoc();
168         this.cacheKeyParList.add(src);
169
170         // Determine the locale
171
String JavaDoc langString = par.getParameter("lang", null);
172         locale = Locale.getDefault();
173         if (langString != null) {
174             this.cacheKeyParList.add(langString);
175             String JavaDoc countryString = par.getParameter("country", "");
176             if (! "".equals(countryString)) {
177                 this.cacheKeyParList.add(countryString);
178             }
179             locale = new Locale JavaDoc(langString, countryString);
180         }
181         
182         // Determine year and month. Default is current year and month.
183
Calendar JavaDoc now = Calendar.getInstance(locale);
184         this.year = par.getParameterAsInteger("year", now.get(Calendar.YEAR));
185         this.cacheKeyParList.add(String.valueOf(this.year));
186         this.month = par.getParameterAsInteger("month", now.get(Calendar.MONTH) + 1) - 1;
187         this.cacheKeyParList.add(String.valueOf(this.month));
188         
189         String JavaDoc dateFormatString = par.getParameter("dateFormat", null);
190         this.cacheKeyParList.add(dateFormatString);
191         if (dateFormatString != null) {
192             this.dateFormatter = new SimpleDateFormat JavaDoc(dateFormatString, locale);
193         } else {
194             this.dateFormatter = DateFormat.getDateInstance(DateFormat.LONG, locale);
195         }
196         this.padWeeks = par.getParameterAsBoolean("padWeeks", false);
197         this.cacheKeyParList.add(BooleanUtils.toBooleanObject(this.padWeeks));
198         this.monthFormatter = new SimpleDateFormat JavaDoc("MMMM", locale);
199         this.attributes = new AttributesImpl JavaDoc();
200     }
201     
202     /**
203      * Generate XML data.
204      *
205      * @throws SAXException if an error occurs while outputting the document
206      */

207     public void generate() throws SAXException JavaDoc, ProcessingException {
208         Calendar JavaDoc start = Calendar.getInstance(locale);
209         start.clear();
210         start.set(Calendar.YEAR, this.year);
211         start.set(Calendar.MONTH, this.month);
212         start.set(Calendar.DAY_OF_MONTH, 1);
213         Calendar JavaDoc end = (Calendar JavaDoc) start.clone();
214         end.add(Calendar.MONTH, 1);
215
216         // Determine previous and next months
217
Calendar JavaDoc prevMonth = (Calendar JavaDoc) start.clone();
218         prevMonth.add(Calendar.MONTH, -1);
219         
220         this.contentHandler.startDocument();
221         this.contentHandler.startPrefixMapping(PREFIX, URI);
222         attributes.clear();
223         attributes.addAttribute("", YEAR_ATTR_NAME, YEAR_ATTR_NAME, "CDATA", String.valueOf(year));
224         attributes.addAttribute("", MONTH_ATTR_NAME, MONTH_ATTR_NAME, "CDATA",
225                 monthFormatter.format(start.getTime()));
226         
227         // Add previous and next month
228
attributes.addAttribute("", PREV_YEAR_ATTR_NAME, PREV_YEAR_ATTR_NAME, "CDATA",
229                 String.valueOf(prevMonth.get(Calendar.YEAR)));
230         attributes.addAttribute("", PREV_MONTH_ATTR_NAME, PREV_MONTH_ATTR_NAME, "CDATA",
231                 monthNumberFormatter.format(prevMonth.get(Calendar.MONTH) + 1));
232         attributes.addAttribute("", NEXT_YEAR_ATTR_NAME, NEXT_YEAR_ATTR_NAME, "CDATA",
233                 String.valueOf(end.get(Calendar.YEAR)));
234         attributes.addAttribute("", NEXT_MONTH_ATTR_NAME, NEXT_MONTH_ATTR_NAME, "CDATA",
235                 monthNumberFormatter.format(end.get(Calendar.MONTH) + 1));
236
237         this.contentHandler.startElement(URI, CALENDAR_NODE_NAME,
238                 PREFIX + ':' + CALENDAR_NODE_NAME, attributes);
239         int weekNo = start.get(Calendar.WEEK_OF_MONTH);
240         int firstDay = start.getFirstDayOfWeek();
241         if (start.get(Calendar.DAY_OF_WEEK) != firstDay) {
242             attributes.clear();
243             attributes.addAttribute("", NUMBER_ATTR_NAME, NUMBER_ATTR_NAME, "CDATA", String.valueOf(weekNo));
244             this.contentHandler.startElement(URI, WEEK_NODE_NAME,
245                     PREFIX + ':' + WEEK_NODE_NAME, attributes);
246             if (padWeeks) {
247                 Calendar JavaDoc previous = (Calendar JavaDoc) start.clone();
248                 while (previous.get(Calendar.DAY_OF_WEEK) != firstDay) {
249                     previous.add(Calendar.DAY_OF_MONTH, -1);
250                 }
251                 while (previous.before(start)) {
252                     attributes.clear();
253                     attributes.addAttribute("", NUMBER_ATTR_NAME, NUMBER_ATTR_NAME, "CDATA",
254                             String.valueOf(previous.get(Calendar.DAY_OF_MONTH)));
255                     attributes.addAttribute("", WEEKDAY_ATTR_NAME, WEEKDAY_ATTR_NAME, "CDATA",
256                             weekdays[previous.get(Calendar.DAY_OF_WEEK)]);
257                     attributes.addAttribute("", DATE_ATTR_NAME, DATE_ATTR_NAME, "CDATA",
258                             dateFormatter.format(previous.getTime()));
259                     this.contentHandler.startElement(URI, DAY_NODE_NAME,
260                             PREFIX + ':' + DAY_NODE_NAME, attributes);
261                     addContent(previous, locale);
262                     this.contentHandler.endElement(URI, DAY_NODE_NAME,
263                             PREFIX + ':' + DAY_NODE_NAME);
264                     previous.add(Calendar.DAY_OF_MONTH, 1);
265                 }
266             }
267         }
268         while (start.before(end)) {
269             if (start.get(Calendar.DAY_OF_WEEK) == firstDay) {
270                 weekNo = start.get(Calendar.WEEK_OF_MONTH);
271                 attributes.clear();
272                 attributes.addAttribute("", NUMBER_ATTR_NAME, NUMBER_ATTR_NAME, "CDATA", String.valueOf(weekNo));
273                 this.contentHandler.startElement(URI, WEEK_NODE_NAME,
274                         PREFIX + ':' + WEEK_NODE_NAME, attributes);
275             }
276             attributes.clear();
277             attributes.addAttribute("", NUMBER_ATTR_NAME, NUMBER_ATTR_NAME, "CDATA",
278                     String.valueOf(start.get(Calendar.DAY_OF_MONTH)));
279             attributes.addAttribute("", WEEKDAY_ATTR_NAME, WEEKDAY_ATTR_NAME, "CDATA",
280                     weekdays[start.get(Calendar.DAY_OF_WEEK)]);
281             attributes.addAttribute("", DATE_ATTR_NAME, DATE_ATTR_NAME, "CDATA",
282                     dateFormatter.format(start.getTime()));
283             this.contentHandler.startElement(URI, DAY_NODE_NAME,
284                     PREFIX + ':' + DAY_NODE_NAME, attributes);
285             addContent(start, locale);
286             this.contentHandler.endElement(URI, DAY_NODE_NAME,
287                     PREFIX + ':' + DAY_NODE_NAME);
288             start.add(Calendar.DAY_OF_MONTH, 1);
289             if (start.get(Calendar.DAY_OF_WEEK) == firstDay
290                     || (!padWeeks && ! start.before(end))) {
291                 this.contentHandler.endElement(URI, WEEK_NODE_NAME,
292                         PREFIX + ':' + WEEK_NODE_NAME);
293             }
294         }
295         
296         if (padWeeks) {
297             while (firstDay != end.get(Calendar.DAY_OF_WEEK)) {
298                 attributes.clear();
299                 attributes.addAttribute("", NUMBER_ATTR_NAME, NUMBER_ATTR_NAME, "CDATA",
300                         String.valueOf(end.get(Calendar.DAY_OF_MONTH)));
301                 attributes.addAttribute("", WEEKDAY_ATTR_NAME, WEEKDAY_ATTR_NAME, "CDATA",
302                         weekdays[end.get(Calendar.DAY_OF_WEEK)]);
303                 attributes.addAttribute("", DATE_ATTR_NAME, DATE_ATTR_NAME, "CDATA",
304                         dateFormatter.format(end.getTime()));
305                 this.contentHandler.startElement(URI, DAY_NODE_NAME,
306                         PREFIX + ':' + DAY_NODE_NAME, attributes);
307                 addContent(end, locale);
308                 this.contentHandler.endElement(URI, DAY_NODE_NAME,
309                         PREFIX + ':' + DAY_NODE_NAME);
310                 end.add(Calendar.DAY_OF_MONTH, 1);
311                 if (firstDay == end.get(Calendar.DAY_OF_WEEK)) {
312                         this.contentHandler.endElement(URI, WEEK_NODE_NAME,
313                            PREFIX + ':' + WEEK_NODE_NAME);
314                 }
315             }
316         }
317         this.contentHandler.endElement(URI, CALENDAR_NODE_NAME,
318                 PREFIX + ':' + CALENDAR_NODE_NAME);
319         this.contentHandler.endPrefixMapping(PREFIX);
320         this.contentHandler.endDocument();
321     }
322     
323     /**
324      * Add content to a &lt;day&gt; element. This method is intended to be overridden
325      * by subclasses that want to add content to one or more days of the calendar.
326      *
327      * @param date The date corresponding to the current element.
328      * @param locale The current locale.
329      * @throws SAXException if an error occurs while outputting the document
330      */

331     protected void addContent(Calendar JavaDoc date, Locale JavaDoc locale) throws SAXException JavaDoc {}
332
333     /* (non-Javadoc)
334      * @see org.apache.cocoon.caching.CacheableProcessingComponent#getKey()
335      */

336     public Serializable JavaDoc getKey() {
337         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
338         int len = this.cacheKeyParList.size();
339         for (int i = 0; i < len; i++) {
340             buffer.append(this.cacheKeyParList.get(i) + ":");
341         }
342         return buffer.toString();
343     }
344     
345     /* (non-Javadoc)
346      * @see org.apache.cocoon.caching.CacheableProcessingComponent#getValidity()
347      */

348     public SourceValidity getValidity() {
349         return NOPValidity.SHARED_INSTANCE;
350     }
351     
352     /**
353      * Recycle resources
354      * @see org.apache.avalon.excalibur.pool.Recyclable#recycle()
355      */

356     public void recycle() {
357         this.cacheKeyParList = null;
358         this.attributes = null;
359         this.dateFormatter = null;
360         this.monthFormatter = null;
361         this.locale = null;
362         super.recycle();
363     }
364
365 }
366
Popular Tags