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.plugin;
020
021import java.text.SimpleDateFormat;
022import java.util.Calendar;
023import java.util.Collection;
024import java.util.Comparator;
025import java.util.Date;
026import java.util.Iterator;
027import java.util.List;
028import java.util.Map;
029import java.util.SortedSet;
030import java.util.TreeSet;
031
032import org.apache.log4j.Logger;
033import org.apache.wiki.WikiContext;
034import org.apache.wiki.WikiEngine;
035import org.apache.wiki.WikiPage;
036import org.apache.wiki.api.exceptions.PluginException;
037import org.apache.wiki.api.exceptions.ProviderException;
038import org.apache.wiki.api.plugin.WikiPlugin;
039import org.apache.wiki.util.TextUtil;
040
041/**
042 *  Creates a list of all weblog entries on a monthly basis.
043 *
044 *  <p>Parameters : </p>
045 *  <ul>
046 *  <li><b>page</b> - the page name</li>
047 *  </ul>
048 *  
049 *  @since 1.9.21
050 */
051public class WeblogArchivePlugin implements WikiPlugin
052{
053    private static Logger     log = Logger.getLogger(WeblogArchivePlugin.class);
054
055    /** Parameter name for setting the page.  Value is <tt>{@value}</tt>. */
056    public static final String PARAM_PAGE = "page";
057
058    private SimpleDateFormat m_monthUrlFormat;
059
060    /**
061     *  {@inheritDoc}
062     */
063    public String execute( WikiContext context, Map<String, String> params )
064        throws PluginException
065    {
066        WikiEngine engine = context.getEngine();
067
068        //
069        //  Parameters
070        //
071        String weblogName = params.get( PARAM_PAGE );
072
073        if( weblogName == null ) weblogName = context.getPage().getName();
074        
075
076        m_monthUrlFormat = new SimpleDateFormat("'"+
077                                                context.getURL( WikiContext.VIEW, weblogName,
078                                                                "weblog.startDate='ddMMyy'&amp;weblog.days=%d")+"'");
079
080        StringBuilder sb = new StringBuilder();
081
082        sb.append( "<div class=\"weblogarchive\">\n" );
083        
084
085        //
086        //  Collect months that have blog entries
087        //
088
089        try
090        {
091            Collection months = collectMonths( engine, weblogName );
092            int year = 0;
093
094            //
095            //  Output proper HTML.
096            //
097
098            sb.append( "<ul>\n" );
099
100            if( months.size() > 0 )
101            {
102                year = ((Calendar)months.iterator().next()).get( Calendar.YEAR );
103
104                sb.append( "<li class=\"archiveyear\">"+year+"</li>\n" );
105            }
106
107            for( Iterator i = months.iterator(); i.hasNext(); )
108            {
109                Calendar cal = (Calendar) i.next();
110
111                if( cal.get( Calendar.YEAR ) != year )
112                {
113                    year = cal.get( Calendar.YEAR );
114
115                    sb.append( "<li class=\"archiveyear\">"+year+"</li>\n" );
116                }
117
118                sb.append( "  <li>" );
119
120                sb.append( getMonthLink( cal ) );
121
122                sb.append( "</li>\n" );
123            }
124
125            sb.append( "</ul>\n" );
126            sb.append( "</div>\n" );
127        }
128        catch( ProviderException ex )
129        {
130            log.info( "Cannot get archive", ex );
131            sb.append("Cannot get archive: "+ex.getMessage());
132        }
133
134        return sb.toString();
135    }
136
137    @SuppressWarnings("unchecked")
138    private SortedSet collectMonths( WikiEngine engine, String page )
139        throws ProviderException
140    {
141        Comparator comp = new ArchiveComparator();
142        TreeSet<Calendar> res = new TreeSet<Calendar>( comp );
143
144        WeblogPlugin pl = new WeblogPlugin();
145
146        List blogEntries = pl.findBlogEntries( engine.getPageManager(),
147                                               page, new Date(0L), new Date() );
148        
149        for( Iterator i = blogEntries.iterator(); i.hasNext(); )
150        {
151            WikiPage p = (WikiPage) i.next();
152
153            // FIXME: Not correct, should parse page creation time.
154
155            Date d = p.getLastModified();
156            Calendar cal = Calendar.getInstance();
157            cal.setTime( d );
158            res.add( cal );
159        }
160
161        return res;
162    }
163
164    private String getMonthLink( Calendar day )
165    {
166        SimpleDateFormat monthfmt = new SimpleDateFormat( "MMMM" );
167        String result;
168
169        if( m_monthUrlFormat == null )
170        {
171            result = monthfmt.format( day.getTime() );
172        }
173        else
174        {
175            Calendar cal = (Calendar)day.clone();
176            int firstDay = cal.getActualMinimum( Calendar.DATE );
177            int lastDay  = cal.getActualMaximum( Calendar.DATE );
178
179            cal.set( Calendar.DATE, lastDay );
180            String url = m_monthUrlFormat.format( cal.getTime() );
181
182            url = TextUtil.replaceString( url, "%d", Integer.toString( lastDay-firstDay+1 ) );
183
184            result = "<a href=\""+url+"\">"+monthfmt.format(cal.getTime())+"</a>";
185        }
186
187        return result;
188
189    }
190
191    
192    /**
193     * This is a simple comparator for ordering weblog archive entries.
194     * Two dates in the same month are considered equal.
195     */
196    private static class ArchiveComparator
197        implements Comparator
198    {
199
200        public int compare( Object a, Object b ) 
201        {
202            if( a == null || b == null || 
203                !(a instanceof Calendar) || !(b instanceof Calendar) )
204            {
205                throw new ClassCastException( "Invalid calendar supplied for comparison." );
206            }
207                    
208            Calendar ca = (Calendar) a;
209            Calendar cb = (Calendar) b;
210            if( ca.get( Calendar.YEAR ) == cb.get( Calendar.YEAR ) &&
211                ca.get( Calendar.MONTH ) == cb.get( Calendar.MONTH ) )
212            {
213                return 0;
214            }
215
216            return cb.getTime().before( ca.getTime() ) ? 1 : -1;
217        }
218    }
219}