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 }