    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.rss;
    020
    021import org.apache.wiki.api.core.Context;
    022import org.apache.wiki.api.core.ContextEnum;
    023import org.apache.wiki.api.core.Engine;
    024import org.apache.wiki.api.core.Page;
    025import org.apache.wiki.util.XhtmlUtil;
    026import org.jdom2.Element;
    027import org.jdom2.Namespace;
    028
    029import java.text.SimpleDateFormat;
    030import java.util.Calendar;
    031
    032
    033/**
    034 * Provides an implementation of an RSS 1.0 feed.  In addition, this class is
    035 * capable of adding RSS 1.0 Wiki Extensions to the Feed, as defined in
    036 * <A HREF="http://usemod.com/cgi-bin/mb.pl?ModWiki">UseMod:ModWiki</A>.
    037 */
    038public class RSS10Feed extends Feed {
    039
    040    private static final Namespace NS_XMNLS = Namespace.getNamespace( "http://purl.org/rss/1.0/" );
    041    private static final Namespace NS_RDF = Namespace.getNamespace( "rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#" );
    042    private static final Namespace NS_DC = Namespace.getNamespace( "dc", "http://purl.org/dc/elements/1.1/" );
    043    private static final Namespace NS_WIKI = Namespace.getNamespace( "wiki", "http://purl.org/rss/1.0/modules/wiki/" );
    044
    045    /**
    046     * Create an RSS 1.0 feed for a given context.
    047     *
    048     * @param context The WikiContext.
    049     */
    050    public RSS10Feed( final Context context ) {
    051        super( context );
    052    }
    053
    054    private Element getRDFItems() {
    055        final Element items = new Element( "items", NS_XMNLS );
    056        final Element rdfseq = new Element( "Seq", NS_RDF );
    057
    058        for( final Entry e : m_entries ) {
    059            final String url = e.getURL();
    060            rdfseq.addContent( new Element( "li", NS_RDF ).setAttribute( "resource", url, NS_RDF ) );
    061        }
    062        items.addContent( rdfseq );
    063
    064        return items;
    065    }
    066
    067    private void addItemList( final Element root ) {
    068        final SimpleDateFormat iso8601fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    069        final Engine engine = m_wikiContext.getEngine();
    070
    071        for( final Entry entry : m_entries ) {
    072            final String url = entry.getURL();
    073
    074            final Element item = new Element( "item", NS_XMNLS );
    075            item.setAttribute( "about", url, NS_RDF );
    076            item.addContent( new Element( "title", NS_XMNLS ).addContent( entry.getTitle() ) );
    077            //FIXME this needs to be an absolute url, not a relative one
    078            item.addContent( new Element( "link", NS_XMNLS ).addContent( url ) );
    079
    080            final Element content = new Element( "description", NS_XMNLS );
    081            // TODO: Add a size limiter here
    082            content.addContent( entry.getContent() );
    083            item.addContent( content );
    084
    085            final Page p = entry.getPage();
    086            if( p.getVersion() != -1 ) {
    087                item.addContent( new Element( "version", NS_WIKI ).addContent( Integer.toString( p.getVersion() ) ) );
    088            }
    089
    090            if( p.getVersion() > 1 ) {
    091                item.addContent( new Element( "diff", NS_WIKI )
    092                                         .addContent( engine.getURL( ContextEnum.PAGE_DIFF.getRequestContext(), p.getName(), "r1=-1" ) ) );
    093            }
    094
    095            //
    096            //  Modification date.
    097            final Calendar cal = Calendar.getInstance();
    098            cal.setTime(p.getLastModified());
    099            cal.add( Calendar.MILLISECOND,
    100                    - ( cal.get( Calendar.ZONE_OFFSET ) +
    101                             ( cal.getTimeZone().inDaylightTime( p.getLastModified() ) ? cal.get( Calendar.DST_OFFSET )
    102                                                                                       : 0 ) ) );
    103
    104            item.addContent( new Element( "date", NS_DC ).addContent( iso8601fmt.format( cal.getTime() ) ) );
    105
    106            //
    107            //  Author
    108            String author = entry.getAuthor();
    109            if( author == null ) {
    110                author = "unknown";
    111            }
    112
    113            final Element contributor = new Element( "creator", NS_DC );
    114            item.addContent( contributor );
    115
    116            /*
    117            Element description = new Element("Description", NS_RDF);
    118            if( m_wikiContext.getEngine().pageExists(author) ) {
    119                description.setAttribute( "link", engine.getURL( WikiContext.VIEW, author, null, true ), NS_XMNLS );
    120            }
    121
    122            description.addContent( new Element("value", NS_XMNLS).addContent( author) );
    123            contributor.addContent( description );
    124           */
    125
    126            // Not too many aggregators seem to like this.  Therefore we're just adding the name here.
    127            contributor.addContent( author );
    128
    129            //
    130            //  PageHistory
    131            item.addContent( new Element( "history", NS_WIKI )
    132                                    .addContent( engine.getURL( ContextEnum.PAGE_INFO.getRequestContext(), p.getName(), null ) ) );
    133
    134            //
    135            // Add to root
    136            root.addContent( item );
    137        }
    138    }
    139
    140    private Element getChannelElement() {
    141        final Element channel = new Element( "channel", NS_XMNLS );
    142        channel.setAttribute( "about", m_feedURL, NS_RDF )
    143               .addContent( new Element( "link", NS_XMNLS ).addContent( m_feedURL ) );
    144
    145        if( m_channelTitle != null ) {
    146            channel.addContent( new Element( "title", NS_XMNLS ).addContent( m_channelTitle ) );
    147        }
    148
    149        if( m_channelDescription != null ) {
    150            channel.addContent( new Element( "description", NS_XMNLS ).addContent( m_channelDescription ) );
    151        }
    152
    153        if( m_channelLanguage != null ) {
    154            channel.addContent( new Element( "language", NS_DC ).addContent( m_channelLanguage ) );
    155        }
    156        channel.addContent( getRDFItems() );
    157
    158        return channel;
    159    }
    160
    161    /**
    162     * {@inheritDoc}
    163     */
    164    @Override
    165    public String getString() {
    166        final Element root = new Element( "RDF", NS_RDF );
    167        root.addContent( getChannelElement() );
    168        root.addNamespaceDeclaration( NS_XMNLS );
    169        root.addNamespaceDeclaration( NS_RDF );
    170        root.addNamespaceDeclaration( NS_DC );
    171        root.addNamespaceDeclaration( NS_WIKI );
    172        addItemList( root );
    173
    174        return XhtmlUtil.serialize( root, true );
    175    }
    176
    177}