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