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            item.addContent( new Element( "link", NS_XMNLS ).addContent( url ) );
078
079            final Element content = new Element( "description", NS_XMNLS );
080            // TODO: Add a size limiter here
081            content.addContent( entry.getContent() );
082            item.addContent( content );
083
084            final Page p = entry.getPage();
085            if( p.getVersion() != -1 ) {
086                item.addContent( new Element( "version", NS_WIKI ).addContent( Integer.toString( p.getVersion() ) ) );
087            }
088
089            if( p.getVersion() > 1 ) {
090                item.addContent( new Element( "diff", NS_WIKI )
091                                         .addContent( engine.getURL( ContextEnum.PAGE_DIFF.getRequestContext(), p.getName(), "r1=-1" ) ) );
092            }
093
094            //
095            //  Modification date.
096            final Calendar cal = Calendar.getInstance();
097            cal.setTime(p.getLastModified());
098            cal.add( Calendar.MILLISECOND,
099                    - ( cal.get( Calendar.ZONE_OFFSET ) +
100                             ( cal.getTimeZone().inDaylightTime( p.getLastModified() ) ? cal.get( Calendar.DST_OFFSET )
101                                                                                       : 0 ) ) );
102
103            item.addContent( new Element( "date", NS_DC ).addContent( iso8601fmt.format( cal.getTime() ) ) );
104
105            //
106            //  Author
107            String author = entry.getAuthor();
108            if( author == null ) {
109                author = "unknown";
110            }
111
112            final Element contributor = new Element( "creator", NS_DC );
113            item.addContent( contributor );
114
115            /*
116            Element description = new Element("Description", NS_RDF);
117            if( m_wikiContext.getEngine().pageExists(author) ) {
118                description.setAttribute( "link", engine.getURL( WikiContext.VIEW, author, null, true ), NS_XMNLS );
119            }
120
121            description.addContent( new Element("value", NS_XMNLS).addContent( author) );
122            contributor.addContent( description );
123           */
124
125            // Not too many aggregators seem to like this.  Therefore we're just adding the name here.
126            contributor.addContent( author );
127
128            //
129            //  PageHistory
130            item.addContent( new Element( "history", NS_WIKI )
131                                    .addContent( engine.getURL( ContextEnum.PAGE_INFO.getRequestContext(), p.getName(), null ) ) );
132
133            //
134            // Add to root
135            root.addContent( item );
136        }
137    }
138
139    private Element getChannelElement() {
140        final Element channel = new Element( "channel", NS_XMNLS );
141        channel.setAttribute( "about", m_feedURL, NS_RDF )
142               .addContent( new Element( "link", NS_XMNLS ).addContent( m_feedURL ) );
143
144        if( m_channelTitle != null ) {
145            channel.addContent( new Element( "title", NS_XMNLS ).addContent( m_channelTitle ) );
146        }
147
148        if( m_channelDescription != null ) {
149            channel.addContent( new Element( "description", NS_XMNLS ).addContent( m_channelDescription ) );
150        }
151
152        if( m_channelLanguage != null ) {
153            channel.addContent( new Element( "language", NS_DC ).addContent( m_channelLanguage ) );
154        }
155        channel.addContent( getRDFItems() );
156
157        return channel;
158    }
159
160    /**
161     * {@inheritDoc}
162     */
163    @Override
164    public String getString() {
165        final Element root = new Element( "RDF", NS_RDF );
166        root.addContent( getChannelElement() );
167        root.addNamespaceDeclaration( NS_XMNLS );
168        root.addNamespaceDeclaration( NS_RDF );
169        root.addNamespaceDeclaration( NS_DC );
170        root.addNamespaceDeclaration( NS_WIKI );
171        addItemList( root );
172
173        return XhtmlUtil.serialize( root, true );
174    }
175
176}