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.rpc.atom;
020    
021    import java.io.IOException;
022    import java.util.Collection;
023    import java.util.Date;
024    import java.util.Iterator;
025    
026    import javax.servlet.ServletConfig;
027    import javax.servlet.ServletException;
028    import javax.servlet.http.HttpServlet;
029    import javax.servlet.http.HttpServletRequest;
030    import javax.servlet.http.HttpServletResponse;
031    
032    import org.apache.log4j.Logger;
033    import org.apache.wiki.WikiContext;
034    import org.apache.wiki.WikiEngine;
035    import org.apache.wiki.WikiPage;
036    import org.apache.wiki.api.exceptions.ProviderException;
037    import org.apache.wiki.api.exceptions.WikiException;
038    import org.apache.wiki.plugin.WeblogEntryPlugin;
039    import org.apache.wiki.plugin.WeblogPlugin;
040    import org.apache.wiki.util.TextUtil;
041    import org.intabulas.sandler.Sandler;
042    import org.intabulas.sandler.SyndicationFactory;
043    import org.intabulas.sandler.elements.Content;
044    import org.intabulas.sandler.elements.Entry;
045    import org.intabulas.sandler.elements.Feed;
046    import org.intabulas.sandler.elements.Link;
047    import org.intabulas.sandler.elements.Person;
048    import org.intabulas.sandler.exceptions.FeedMarshallException;
049    
050    
051    /**
052     *  Handles incoming requests for the Atom API.  This class uses the
053     *  "sandler" Atom API implementation.
054     *
055     *  @since 2.1.97
056     */
057    // FIXME: Rewrite using some other library
058    public class AtomAPIServlet extends HttpServlet
059    {
060        static final Logger log = Logger.getLogger( AtomAPIServlet.class );
061    
062        private static final long serialVersionUID = 0L;
063    
064        private WikiEngine       m_engine;
065    
066        /**
067         *  {@inheritDoc}
068         */
069        public void init( ServletConfig config )
070            throws ServletException
071        {
072            m_engine = WikiEngine.getInstance( config );
073        }
074    
075        /**
076         *  Takes the name of the page from the request URI.
077         *  The initial slash is also removed.  If there is no page,
078         *  returns null.
079         */
080        private String getPageName( HttpServletRequest request )
081        {
082            String name = request.getPathInfo();
083    
084            if( name == null || name.length() <= 1 )
085            {
086                return null;
087            }
088            else if( name.charAt(0) == '/' )
089            {
090                name = name.substring(1);
091            }
092    
093            name = TextUtil.urlDecodeUTF8( name );
094    
095            return name;
096        }
097    
098        /**
099         *  Implements the PostURI of the Atom spec.
100         *  <p>
101         *  Implementation notes:
102         *  <ul>
103         *   <li>Only fetches the first content.  All other contents are ignored.
104         *   <li>Assumes that incoming code is plain text or WikiMarkup, not html.
105         *  </ul>
106         *  
107         *  @param request {@inheritDoc}
108         *  @param response {@inheritDoc}
109         *  @throws ServletException {@inheritDoc}
110         */
111        public void doPost( HttpServletRequest request, HttpServletResponse response )
112            throws ServletException
113        {
114            log.debug("Received POST to AtomAPIServlet");
115    
116            try
117            {
118                String blogid = getPageName( request );
119    
120                WikiPage page    = m_engine.getPage( blogid );
121    
122                if( page == null )
123                {
124                    throw new ServletException("Page "+blogid+" does not exist, cannot add blog post.");
125                }
126    
127                //FIXME: Do authentication here
128                Entry entry = Sandler.unmarshallEntry( request.getInputStream() );
129    
130                //
131                //  Fetch the obligatory parts of the content.
132                //
133                Content title   = entry.getTitle();
134                Content content = entry.getContent(0);
135    
136                Person  author  = entry.getAuthor();
137    
138                //FIXME: Sandler 0.5 does not support generator
139    
140                //
141                //  Generate new blog entry.
142                //
143                WeblogEntryPlugin plugin = new WeblogEntryPlugin();
144    
145                String pageName = plugin.getNewEntryPage( m_engine, blogid );
146                String username = author.getName();
147    
148                WikiPage entryPage = new WikiPage( m_engine, pageName );
149                entryPage.setAuthor( username );
150    
151                WikiContext context = new WikiContext( m_engine, request, entryPage );
152    
153                StringBuffer text = new StringBuffer();
154                text.append( "!"+title.getBody() );
155                text.append( "\n\n" );
156                text.append( content.getBody() );
157    
158                log.debug("Writing entry: "+text);
159    
160                m_engine.saveText( context, text.toString() );
161    
162            }
163            catch( FeedMarshallException e )
164            {
165                log.error("Received faulty Atom entry",e);
166                throw new ServletException("Faulty Atom entry",e);
167            }
168            catch( IOException e )
169            {
170                log.error("I/O exception",e);
171                throw new ServletException("Could not get body of request",e);
172            }
173            catch( WikiException e )
174            {
175                log.error("Provider exception while posting",e);
176                throw new ServletException("JSPWiki cannot save the entry",e);
177            }
178        }
179    
180        /**
181         *  Handles HTTP GET.  However, we do not respond to GET requests,
182         *  other than to show an explanatory text.
183         *  
184         *  {@inheritDoc}
185         */
186        public void doGet( HttpServletRequest request, HttpServletResponse response )
187            throws ServletException
188        {
189            log.debug("Received HTTP GET to AtomAPIServlet");
190    
191            String blogid = getPageName( request );
192    
193            log.debug("Requested page "+blogid);
194    
195            try
196            {
197                if( blogid == null )
198                {
199                    Feed feed = listBlogs();
200    
201                    response.setContentType("application/x.atom+xml; charset=UTF-8");
202                    response.getWriter().println( Sandler.marshallFeed(feed) );
203    
204                    response.getWriter().flush();
205                }
206                else
207                {
208                    Entry entry = getBlogEntry( blogid );
209    
210                    response.setContentType("application/x.atom+xml; charset=UTF-8");
211                    response.getWriter().println( Sandler.marshallEntry(entry) );
212    
213                    response.getWriter().flush();
214                }
215            }
216            catch( Exception e )
217            {
218                log.error("Unable to generate response",e);
219                throw new ServletException("Internal problem - whack Janne on the head to get a better error report",e);
220            }
221    
222        }
223    
224        private Entry getBlogEntry( String entryid )
225            throws ProviderException
226        {
227            WikiPage page = m_engine.getPage( entryid );
228            WikiPage firstVersion = m_engine.getPage( entryid, 1 );
229    
230            Entry entry = SyndicationFactory.newSyndicationEntry();
231    
232            String pageText = m_engine.getText(page.getName());
233            String title = "";
234            int firstLine = pageText.indexOf('\n');
235    
236            if( firstLine > 0 )
237            {
238                title = pageText.substring( 0, firstLine );
239            }
240    
241            if( title.trim().length() == 0 ) title = page.getName();
242    
243            // Remove wiki formatting
244            while( title.startsWith("!") ) title = title.substring(1);
245    
246            entry.setTitle( title );
247            entry.setCreated( firstVersion.getLastModified() );
248            entry.setModified( page.getLastModified() );
249            entry.setAuthor( SyndicationFactory.createPerson( page.getAuthor(),
250                                                              null,
251                                                              null ) );
252    
253            entry.addContent( SyndicationFactory.createEscapedContent(pageText) );
254    
255            return entry;
256        }
257    
258        /**
259         *  Creates and outputs a full list of all available blogs
260         */
261        private Feed listBlogs()
262            throws ProviderException,
263                   IOException
264        {
265            Collection pages = m_engine.getPageManager().getAllPages();
266    
267            Feed feed = SyndicationFactory.newSyndicationFeed();
268            feed.setTitle("List of blogs at this site");
269            feed.setModified( new Date() );
270    
271            for( Iterator i = pages.iterator(); i.hasNext(); )
272            {
273                WikiPage p = (WikiPage) i.next();
274    
275                //
276                //  List only weblogs
277                //  FIXME: Unfortunately, a weblog is not known until it has
278                //         been executed once, because plugins are off during
279                //         the initial startup phase.
280                //
281    
282                log.debug( p.getName()+" = "+p.getAttribute(WeblogPlugin.ATTR_ISWEBLOG)) ;
283    
284                if( !("true".equals(p.getAttribute(WeblogPlugin.ATTR_ISWEBLOG)) ) )
285                    continue;
286    
287                String encodedName = TextUtil.urlEncodeUTF8( p.getName() );
288    
289                WikiContext context = new WikiContext( m_engine, p );
290    
291                String title = TextUtil.replaceEntities(org.apache.wiki.rss.Feed.getSiteName(context));
292    
293                Link postlink = createLink( "service.post",
294                                            m_engine.getBaseURL()+"atom/"+encodedName,
295                                            title );
296    
297                Link editlink = createLink( "service.edit",
298                                            m_engine.getBaseURL()+"atom/"+encodedName,
299                                            title );
300    
301                Link feedlink = createLink( "service.feed",
302                                            m_engine.getBaseURL()+"atom.jsp?page="+encodedName,
303                                            title );
304    
305    
306                feed.addLink( postlink );
307                feed.addLink( feedlink );
308                feed.addLink( editlink );
309            }
310    
311            return feed;
312        }
313    
314        private Link createLink( String rel,
315                                 String href,
316                                 String title )
317        {
318            org.intabulas.sandler.elements.impl.LinkImpl link = new org.intabulas.sandler.elements.impl.LinkImpl();
319    
320            link.setRelationship( rel );
321            link.setTitle( title );
322            link.setType( "application/x.atom+xml" );
323            link.setHref( href );
324    
325            return link;
326        }
327    
328        /**
329         *  {@inheritDoc}
330         */
331        public void doDelete( HttpServletRequest request, HttpServletResponse response )
332            throws ServletException
333        {
334            log.debug("Received HTTP DELETE");
335        }
336    
337        /**
338         *  {@inheritDoc}
339         */
340        public void doPut( HttpServletRequest request, HttpServletResponse response )
341            throws ServletException
342        {
343            log.debug("Received HTTP PUT");
344        }
345    }