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