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