    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.commons.lang3.time.DateFormatUtils;
    022import org.apache.wiki.api.Release;
    023import org.apache.wiki.api.core.Attachment;
    024import org.apache.wiki.api.core.Context;
    025import org.apache.wiki.api.core.ContextEnum;
    026import org.apache.wiki.api.core.Engine;
    027import org.apache.wiki.api.core.Page;
    028import org.apache.wiki.api.exceptions.ProviderException;
    029import org.apache.wiki.attachment.AttachmentManager;
    030import org.jdom2.Element;
    031import org.jdom2.Namespace;
    032import org.jdom2.output.Format;
    033import org.jdom2.output.XMLOutputter;
    034
    035import javax.servlet.ServletContext;
    036import java.io.IOException;
    037import java.io.StringWriter;
    038import java.util.ArrayList;
    039import java.util.Collection;
    040import java.util.Date;
    041import java.util.List;
    042
    043/**
    044 *  Provides an Atom 1.0 standard feed, with enclosures.
    045 *
    046 */
    047public class AtomFeed extends Feed {
    048
    049    private final Namespace m_atomNameSpace = Namespace.getNamespace("http://www.w3.org/2005/Atom");
    050
    051    /** Defines a SimpleDateFormat string for RFC3339-formatted dates. */
    052    public static final String RFC3339FORMAT = "yyyy-MM-dd'T'HH:mm:ssZZ";
    053
    054    /**
    055     *  Create a new AtomFeed for a given WikiContext.
    056     *
    057     *  @param c A WikiContext.
    058     */
    059    public AtomFeed( final Context c )
    060    {
    061        super(c);
    062    }
    063
    064    /**
    065     *   This is a bit complicated right now, as there is no proper metadata store in JSPWiki.
    066     *
    067     *   @return An unique feed ID.
    068     */
    069    private String getFeedID()
    070    {
    071        return m_wikiContext.getEngine().getBaseURL(); // FIXME: This is not a feed id
    072    }
    073
    074    private String getEntryID( final Entry e )
    075    {
    076        return e.getURL(); // FIXME: Not really a feed id!
    077    }
    078
    079    private Collection<Element> getItems() {
    080        final ArrayList< Element > list = new ArrayList<>();
    081        final Engine engine = m_wikiContext.getEngine();
    082        ServletContext servletContext = null;
    083        if( m_wikiContext.getHttpRequest() != null ) {
    084            servletContext = m_wikiContext.getHttpRequest().getSession().getServletContext();
    085        }
    086
    087        for( final Entry e : m_entries ) {
    088            final Page p = e.getPage();
    089            final Element entryEl = getElement( "entry" );
    090
    091            //  Mandatory elements
    092            entryEl.addContent( getElement( "id" ).setText( getEntryID( e ) ) );
    093            entryEl.addContent( getElement( "title" ).setAttribute( "type", "html" ).setText( e.getTitle() ) );
    094            entryEl.addContent( getElement( "updated" ).setText( DateFormatUtils.formatUTC( p.getLastModified(), RFC3339FORMAT ) ) );
    095
    096            //  Optional elements
    097            entryEl.addContent( getElement( "author" ).addContent( getElement( "name" ).setText( e.getAuthor() ) ) );
    098            entryEl.addContent( getElement( "link" ).setAttribute( "rel", "alternate" ).setAttribute( "href", e.getURL() ) );
    099            entryEl.addContent( getElement( "content" ).setAttribute( "type", "html" ).setText( e.getContent() ) );
    100
    101            //  Check for enclosures
    102            if( engine.getManager( AttachmentManager.class ).hasAttachments( p ) && servletContext != null ) {
    103                try {
    104                    final List< Attachment > c = engine.getManager( AttachmentManager.class ).listAttachments( p );
    105                    for( final Attachment att : c ) {
    106                        final Element attEl = getElement( "link" );
    107                        attEl.setAttribute( "rel", "enclosure" );
    108                        attEl.setAttribute( "href", engine.getURL( ContextEnum.PAGE_ATTACH.getRequestContext(), att.getName(), null ) );
    109                        attEl.setAttribute( "length", Long.toString( att.getSize() ) );
    110                        attEl.setAttribute( "type", getMimeType( servletContext, att.getFileName() ) );
    111
    112                        entryEl.addContent( attEl );
    113                    }
    114                } catch( final ProviderException ex ) {
    115                    // FIXME: LOG.info("Can't get attachment data",ex);
    116                }
    117            }
    118
    119            list.add( entryEl );
    120        }
    121
    122        return list;
    123    }
    124
    125    /**
    126     *  {@inheritDoc}
    127     */
    128    @Override
    129    public String getString() {
    130        final Element root = getElement("feed");
    131        final Engine engine = m_wikiContext.getEngine();
    132
    133        Date lastModified = new Date(0L);
    134
    135        for( final Entry e : m_entries ) {
    136            if( e.getPage().getLastModified().after( lastModified ) ) {
    137                lastModified = e.getPage().getLastModified();
    138            }
    139        }
    140
    141        //  Mandatory parts
    142        root.addContent( getElement( "title" ).setText( getChannelTitle() ) );
    143        root.addContent( getElement( "id" ).setText( getFeedID() ) );
    144        root.addContent( getElement( "updated" ).setText( DateFormatUtils.formatUTC( lastModified, RFC3339FORMAT ) ) );
    145
    146        //  Optional
    147        // root.addContent( getElement("author").addContent(getElement("name").setText(format())))
    148        root.addContent( getElement( "link" ).setAttribute( "href", engine.getBaseURL() ) );
    149        root.addContent( getElement( "generator" ).setText( "JSPWiki " + Release.VERSTR ) );
    150
    151        final String rssFeedURL  = engine.getURL( ContextEnum.PAGE_NONE.getRequestContext(), "rss.jsp",
    152                                                 "page=" + engine.encodeName( m_wikiContext.getPage().getName() ) +
    153                                                 "&mode=" + m_mode +
    154                                                 "&type=atom" );
    155        final Element self = getElement( "link" ).setAttribute( "rel","self" );
    156        self.setAttribute( "href", rssFeedURL );
    157        root.addContent( self );
    158
    159        //  Items
    160        root.addContent( getItems() );
    161
    162        //  aaand output
    163        final XMLOutputter output = new XMLOutputter();
    164        output.setFormat( Format.getPrettyFormat() );
    165
    166        try {
    167            final StringWriter res = new StringWriter();
    168            output.output( root, res );
    169
    170            return res.toString();
    171        } catch( final IOException e ) {
    172            return null;
    173        }
    174    }
    175
    176    private Element getElement( final String name ) {
    177        return new Element( name, m_atomNameSpace );
    178    }
    179
    180}