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.rpc.atom; 020 021import java.io.IOException; 022import java.util.Collection; 023import java.util.Date; 024import java.util.Iterator; 025 026import javax.servlet.ServletConfig; 027import javax.servlet.ServletException; 028import javax.servlet.http.HttpServlet; 029import javax.servlet.http.HttpServletRequest; 030import javax.servlet.http.HttpServletResponse; 031 032import org.apache.log4j.Logger; 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.api.exceptions.WikiException; 038import org.apache.wiki.plugin.WeblogEntryPlugin; 039import org.apache.wiki.plugin.WeblogPlugin; 040import org.apache.wiki.util.TextUtil; 041import org.intabulas.sandler.Sandler; 042import org.intabulas.sandler.SyndicationFactory; 043import org.intabulas.sandler.elements.Content; 044import org.intabulas.sandler.elements.Entry; 045import org.intabulas.sandler.elements.Feed; 046import org.intabulas.sandler.elements.Link; 047import org.intabulas.sandler.elements.Person; 048import 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 058public 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 StringBuilder text = new StringBuilder(); 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< WikiPage > 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< WikiPage > i = pages.iterator(); i.hasNext(); ) 272 { 273 WikiPage p = 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}