001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.tags; 020 021import org.apache.logging.log4j.LogManager; 022import org.apache.logging.log4j.Logger; 023import org.apache.wiki.api.core.ContextEnum; 024import org.apache.wiki.api.core.Engine; 025import org.apache.wiki.api.core.Page; 026import org.apache.wiki.pages.PageManager; 027import org.apache.wiki.util.HttpUtil; 028import org.apache.wiki.util.TextUtil; 029 030import javax.servlet.http.HttpServletRequest; 031import javax.servlet.jsp.JspWriter; 032import java.io.IOException; 033import java.text.ParseException; 034import java.text.SimpleDateFormat; 035import java.util.Calendar; 036import java.util.Date; 037 038 039/** 040 * Provides a nice calendar. Responds to the following HTTP parameters: 041 * <ul> 042 * <li>calendar.date - If this parameter exists, then the calendar 043 * date is taken from the month and year. The date must be in ddMMyy 044 * format. 045 * <li>weblog.startDate - If calendar.date parameter does not exist, 046 * we then check this date. 047 * </ul> 048 * 049 * If neither calendar.date nor weblog.startDate parameters exist, 050 * then the calendar will default to the current month. 051 * 052 * @since 2.0 053 */ 054 055// FIXME: This class is extraordinarily lacking. 056public class CalendarTag extends WikiTagBase { 057 058 private static final long serialVersionUID = 0L; 059 private static final Logger LOG = LogManager.getLogger( CalendarTag.class ); 060 061 private SimpleDateFormat m_pageFormat; 062 private SimpleDateFormat m_urlFormat; 063 private SimpleDateFormat m_monthUrlFormat; 064 private SimpleDateFormat m_dateFormat = new SimpleDateFormat( "ddMMyy" ); 065 066 /** 067 * {@inheritDoc} 068 */ 069 @Override 070 public void initTag() 071 { 072 super.initTag(); 073 m_pageFormat = m_urlFormat = m_monthUrlFormat = null; 074 m_dateFormat = new SimpleDateFormat( "ddMMyy" ); 075 } 076 077 /* 078 public void setYear( String year ) 079 { 080 m_year = year; 081 } 082 083 public void setMonth( String month ) 084 { 085 m_month = month; 086 } 087 */ 088 089 /** 090 * Sets the page format. If a page corresponding to the format is found when 091 * the calendar is being rendered, a link to that page is created. E.g. if the 092 * format is set to <tt>'Main_blogentry_'ddMMyy</tt>, it works nicely in 093 * conjunction to the WeblogPlugin. 094 * 095 * @param format The format in the SimpleDateFormat fashion. 096 * 097 * @see SimpleDateFormat 098 * @see org.apache.wiki.plugin.WeblogPlugin 099 */ 100 public void setPageformat( final String format ) 101 { 102 m_pageFormat = new SimpleDateFormat( format ); 103 } 104 105 /** 106 * Set the URL format. If the pageformat is not set, all dates are 107 * links to pages according to this format. The pageformat 108 * takes precedence. 109 * 110 * @param format The URL format in the SimpleDateFormat fashion. 111 * @see SimpleDateFormat 112 */ 113 public void setUrlformat( final String format ) 114 { 115 m_urlFormat = new SimpleDateFormat( format ); 116 } 117 118 /** 119 * Set the format to be used for links for the months. 120 * 121 * @param format The format to set in the SimpleDateFormat fashion. 122 * 123 * @see SimpleDateFormat 124 */ 125 public void setMonthurlformat( final String format ) 126 { 127 m_monthUrlFormat = new SimpleDateFormat( format ); 128 } 129 130 private String format( final String txt ) { 131 final Page p = m_wikiContext.getPage(); 132 if( p != null ) { 133 return TextUtil.replaceString( txt, "%p", p.getName() ); 134 } 135 136 return txt; 137 } 138 139 /** 140 * Returns a link to the given day. 141 */ 142 private String getDayLink( final Calendar day ) { 143 final Engine engine = m_wikiContext.getEngine(); 144 final String result; 145 146 if( m_pageFormat != null ) { 147 final String pagename = m_pageFormat.format( day.getTime() ); 148 149 if( engine.getManager( PageManager.class ).wikiPageExists( pagename ) ) { 150 if( m_urlFormat != null ) { 151 final String url = m_urlFormat.format( day.getTime() ); 152 result = "<td class=\"link\"><a href=\""+url+"\">"+day.get( Calendar.DATE )+"</a></td>"; 153 } else { 154 result = "<td class=\"link\"><a href=\""+m_wikiContext.getViewURL( pagename )+"\">"+ 155 day.get( Calendar.DATE )+"</a></td>"; 156 } 157 } else { 158 result = "<td class=\"days\">"+day.get(Calendar.DATE)+"</td>"; 159 } 160 } else if( m_urlFormat != null ) { 161 final String url = m_urlFormat.format( day.getTime() ); 162 result = "<td><a href=\""+url+"\">"+day.get( Calendar.DATE )+"</a></td>"; 163 } else { 164 result = "<td class=\"days\">"+day.get(Calendar.DATE)+"</td>"; 165 } 166 167 return format( result ); 168 } 169 170 private String getMonthLink( final Calendar day ) { 171 final SimpleDateFormat monthfmt = new SimpleDateFormat( "MMMM yyyy" ); 172 final String result; 173 174 if( m_monthUrlFormat == null ) { 175 result = monthfmt.format( day.getTime() ); 176 } else { 177 final Calendar cal = (Calendar)day.clone(); 178 final int firstDay = cal.getActualMinimum( Calendar.DATE ); 179 final int lastDay = cal.getActualMaximum( Calendar.DATE ); 180 181 cal.set( Calendar.DATE, lastDay ); 182 String url = m_monthUrlFormat.format( cal.getTime() ); 183 184 url = TextUtil.replaceString( url, "%d", Integer.toString( lastDay - firstDay + 1 ) ); 185 186 result = "<a href=\""+url+"\">"+monthfmt.format(cal.getTime())+"</a>"; 187 } 188 189 return format( result ); 190 } 191 192 private String getMonthNaviLink( final Calendar day, final String txt, String queryString ) { 193 final String result; 194 queryString = TextUtil.replaceEntities( queryString ); 195 final Calendar nextMonth = Calendar.getInstance(); 196 nextMonth.set( Calendar.DATE, 1 ); 197 nextMonth.add( Calendar.DATE, -1); 198 nextMonth.add( Calendar.MONTH, 1 ); // Now move to 1st day of next month 199 200 if ( day.before( nextMonth ) ) { 201 final Page thePage = m_wikiContext.getPage(); 202 final String pageName = thePage.getName(); 203 204 final String calendarDate = m_dateFormat.format( day.getTime() ); 205 String url = m_wikiContext.getURL( ContextEnum.PAGE_VIEW.getRequestContext(), pageName,"calendar.date="+calendarDate ); 206 final int queryStringLlength = queryString.length(); 207 if(queryStringLlength > 0) { 208 // 209 // Ensure that the 'calendar.date=ddMMyy' has been removed from the queryString 210 // 211 212 // FIXME: Might be useful to have an entire library of 213 // routines for this. Will fail if it's not calendar.date 214 // but something else. 215 216 final int pos1 = queryString.indexOf("calendar.date="); 217 if( pos1 >= 0 ) { 218 String tmp = queryString.substring( 0, pos1 ); 219 // FIXME: Will this fail when we use & instead of &? 220 // FIXME: should use some parsing routine 221 final int pos2 = queryString.indexOf("&", pos1 ) + 1; 222 if ( ( pos2 > 0 ) && ( pos2 < queryStringLlength ) ) { 223 tmp = tmp + queryString.substring(pos2); 224 } 225 queryString = tmp; 226 } 227 228 if( queryStringLlength > 0 ) { 229 url = url + "&" + queryString; 230 } 231 } 232 result = "<td><a href=\""+url+"\">"+txt+"</a></td>"; 233 } else { 234 result="<td> </td>"; 235 } 236 237 return format( result ); 238 } 239 240 /** 241 * {@inheritDoc} 242 */ 243 @Override 244 public final int doWikiStartTag() throws IOException { 245 final Engine engine = m_wikiContext.getEngine(); 246 final JspWriter out = pageContext.getOut(); 247 final Calendar cal = Calendar.getInstance(); 248 final Calendar prevCal = Calendar.getInstance(); 249 final Calendar nextCal = Calendar.getInstance(); 250 251 // 252 // Check if there is a parameter in the request to set the date. 253 // 254 String calendarDate = pageContext.getRequest().getParameter( "calendar.date" ); 255 if( calendarDate == null ) { 256 calendarDate = pageContext.getRequest().getParameter( "weblog.startDate" ); 257 } 258 259 if( calendarDate != null ) { 260 try { 261 final Date d = m_dateFormat.parse( calendarDate ); 262 cal.setTime( d ); 263 prevCal.setTime( d ); 264 nextCal.setTime( d ); 265 } catch( final ParseException e ) { 266 LOG.warn( "date format wrong: " + calendarDate ); 267 } 268 } 269 270 cal.set( Calendar.DATE, 1 ); // First, set to first day of month 271 prevCal.set( Calendar.DATE, 1 ); 272 nextCal.set( Calendar.DATE, 1 ); 273 274 prevCal.add(Calendar.MONTH, -1); // Now move to first day of previous month 275 nextCal.add(Calendar.MONTH, 1); // Now move to first day of next month 276 277 out.write( "<table class=\"calendar\">\n" ); 278 279 final HttpServletRequest httpServletRequest = m_wikiContext.getHttpRequest(); 280 final String queryString = HttpUtil.safeGetQueryString( httpServletRequest, engine.getContentEncoding() ); 281 out.write( "<tr>"+ 282 getMonthNaviLink(prevCal,"<<", queryString)+ 283 "<td colspan=5 class=\"month\">"+ 284 getMonthLink( cal )+ 285 "</td>"+ 286 getMonthNaviLink(nextCal,">>", queryString)+ 287 "</tr>\n" 288 ); 289 290 final int month = cal.get( Calendar.MONTH ); 291 cal.set( Calendar.DAY_OF_WEEK, Calendar.MONDAY ); // Then, find the first day of the week. 292 293 out.write( "<tr><td class=\"weekdays\">Mon</td>"+ 294 "<td class=\"weekdays\">Tue</td>"+ 295 "<td class=\"weekdays\">Wed</td>"+ 296 "<td class=\"weekdays\">Thu</td>"+ 297 "<td class=\"weekdays\">Fri</td>"+ 298 "<td class=\"weekdays\">Sat</td>"+ 299 "<td class=\"weekdays\">Sun</td></tr>\n" ); 300 301 boolean noMoreDates = false; 302 while( !noMoreDates ) { 303 out.write( "<tr>" ); 304 305 for( int i = 0; i < 7; i++ ) { 306 final int mth = cal.get( Calendar.MONTH ); 307 308 if( mth != month ) { 309 out.write("<td class=\"othermonth\">"+cal.get(Calendar.DATE)+"</td>"); 310 } else { 311 out.write( getDayLink(cal) ); 312 } 313 314 cal.add( Calendar.DATE, 1 ); 315 } 316 317 if( cal.get( Calendar.MONTH ) != month ) { 318 noMoreDates = true; 319 } 320 321 out.write( "</tr>\n" ); 322 } 323 324 out.write( "</table>\n" ); 325 326 return EVAL_BODY_INCLUDE; 327 } 328 329}