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     */
019    package org.apache.wiki.rss;
020    
021    import java.io.IOException;
022    import java.io.StringWriter;
023    import java.util.ArrayList;
024    import java.util.Collection;
025    import java.util.Date;
026    import java.util.Iterator;
027    
028    import javax.servlet.ServletContext;
029    
030    import org.apache.commons.lang.time.DateFormatUtils;
031    import org.jdom2.Element;
032    import org.jdom2.Namespace;
033    import org.jdom2.output.Format;
034    import org.jdom2.output.XMLOutputter;
035    import org.apache.wiki.Release;
036    import org.apache.wiki.WikiContext;
037    import org.apache.wiki.WikiEngine;
038    import org.apache.wiki.WikiPage;
039    import org.apache.wiki.api.exceptions.ProviderException;
040    import org.apache.wiki.attachment.Attachment;
041    
042    /**
043     *  Provides an Atom 1.0 standard feed, with enclosures.
044     *
045     */
046    public 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    }