File Source: FeedServlet.java
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. The ASF licenses this file to You
4 * under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License. For additional information regarding
15 * copyright in this work, please see the NOTICE file in the top level
16 * directory of this distribution.
17 */
18
19 package org.apache.roller.weblogger.ui.rendering.servlets;
20
21 import java.io.IOException;
22 import java.util.HashMap;
23 import java.util.Map;
24 import javax.servlet.ServletConfig;
25 import javax.servlet.ServletException;
26 import javax.servlet.http.HttpServlet;
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletResponse;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.roller.weblogger.WebloggerException;
32 import org.apache.roller.weblogger.business.WebloggerFactory;
33 import org.apache.roller.weblogger.business.WeblogManager;
34 import org.apache.roller.weblogger.config.WebloggerConfig;
35 import org.apache.roller.weblogger.config.WebloggerRuntimeConfig;
36 import org.apache.roller.weblogger.pojos.StaticTemplate;
37 import org.apache.roller.weblogger.pojos.Template;
38 import org.apache.roller.weblogger.pojos.Weblog;
39 import org.apache.roller.weblogger.ui.rendering.util.WeblogFeedRequest;
40 import org.apache.roller.weblogger.util.cache.CachedContent;
41 import org.apache.roller.weblogger.ui.rendering.Renderer;
42 import org.apache.roller.weblogger.ui.rendering.RendererManager;
43 import org.apache.roller.weblogger.ui.rendering.model.ModelLoader;
44 import org.apache.roller.weblogger.ui.rendering.model.SearchResultsFeedModel;
45 import org.apache.roller.weblogger.ui.rendering.util.cache.SiteWideCache;
46 import org.apache.roller.weblogger.ui.rendering.util.cache.WeblogFeedCache;
47 import org.apache.roller.weblogger.ui.rendering.util.ModDateHeaderUtil;
48
49
50 /**
51 * Responsible for rendering weblog feeds.
52 *
53 * @web.servlet name="FeedServlet" load-on-startup="5"
54 * @web.servlet-mapping url-pattern="/roller-ui/rendering/feed/*"
55 */
/*
P/P * Method: void org.apache.roller.weblogger.ui.rendering.servlets.FeedServlet()
*
* Postconditions:
* this.siteWideCache == null
* this.weblogFeedCache == null
*/
56 public class FeedServlet extends HttpServlet {
57
/*
P/P * Method: org.apache.roller.weblogger.ui.rendering.servlets.FeedServlet__static_init
*
* Postconditions:
* init'ed(log)
*/
58 private static Log log = LogFactory.getLog(FeedServlet.class);
59
60 private WeblogFeedCache weblogFeedCache = null;
61 private SiteWideCache siteWideCache = null;
62
63
64 /**
65 * Init method for this servlet
66 */
67 public void init(ServletConfig servletConfig) throws ServletException {
68
/*
P/P * Method: void init(ServletConfig)
*
* Preconditions:
* log != null
*
* Postconditions:
* init'ed(this.siteWideCache)
* init'ed(this.weblogFeedCache)
*/
69 super.init(servletConfig);
70
71 log.info("Initializing FeedServlet");
72
73 // get a reference to the weblog feed cache
74 this.weblogFeedCache = WeblogFeedCache.getInstance();
75
76 // get a reference to the site wide cache
77 this.siteWideCache = SiteWideCache.getInstance();
78 }
79
80
81 /**
82 * Handle GET requests for weblog feeds.
83 */
84 public void doGet(HttpServletRequest request, HttpServletResponse response)
85 throws ServletException, IOException {
86
/*
P/P * Method: void doGet(HttpServletRequest, HttpServletResponse)
*
* Preconditions:
* log != null
* (soft) org/apache/roller/weblogger/ui/rendering/RendererManager.rendererFactories != null
* (soft) org/apache/roller/weblogger/ui/rendering/model/ModelLoader.log != null
* (soft) org/apache/roller/weblogger/util/cache/CachedContent.log != null
* (soft) request != null
* (soft) response != null
* (soft) this.siteWideCache != null
* (soft) this.weblogFeedCache != null
*
* Presumptions:
* cachedContent.content@157 != null
* cachedContent.content@159 != null
* getContent(...).length@157 <= 232-1
* getContent(...).length@159 <= 232-1
* getContent(...).length@291 <= 232-1
* ...
*
* Test Vectors:
* java.lang.String:equals(...)@140: {0}, {1}
* java.lang.String:equals(...)@142: {0}, {1}
* java.lang.String:equals(...)@246: {0}, {1}
* java.lang.String:indexOf(...)@133: {-1}, {-231..-2, 0..232-1}
* java.lang.String:startsWith(...)@133: {0}, {1}
* java.util.List:size(...)@191: {-231..0}, {1..232-1}
* javax.servlet.http.HttpServletRequest:getHeader(...)@131: Addr_Set{null}, Inverse{null}
* javax.servlet.http.HttpServletRequest:getHeader(...)@132: Addr_Set{null}, Inverse{null}
* javax.servlet.http.HttpServletResponse:isCommitted(...)@203: {1}, {0}
* org.apache.roller.weblogger.config.WebloggerRuntimeConfig:getBooleanProperty(...)@133: {0}, {1}
* ...
*/
87 log.debug("Entering");
88
89 Weblog weblog = null;
90 boolean isSiteWide = false;
91
92 WeblogFeedRequest feedRequest = null;
93 try {
94 // parse the incoming request and extract the relevant data
95 feedRequest = new WeblogFeedRequest(request);
96
97 weblog = feedRequest.getWeblog();
98 if(weblog == null) {
99 throw new WebloggerException("unable to lookup weblog: "+
100 feedRequest.getWeblogHandle());
101 }
102
103 // is this the site-wide weblog?
104 isSiteWide = WebloggerRuntimeConfig.isSiteWideWeblog(feedRequest.getWeblogHandle());
105
106 } catch(Exception e) {
107 // invalid feed request format or weblog doesn't exist
108 log.debug("error creating weblog feed request", e);
109 response.sendError(HttpServletResponse.SC_NOT_FOUND);
110 return;
111 }
112
113
114 // determine the lastModified date for this content
115 long lastModified = System.currentTimeMillis();
116 if(isSiteWide) {
117 lastModified = siteWideCache.getLastModified().getTime();
118 } else if (weblog.getLastModified() != null) {
119 lastModified = weblog.getLastModified().getTime();
120 }
121
122 // Respond with 304 Not Modified if it is not modified.
123 if (ModDateHeaderUtil.respondIfNotModified(request,response,lastModified)) {
124 return;
125 }
126
127 // set last-modified date
128 ModDateHeaderUtil.setLastModifiedHeader(response, lastModified);
129
130 // set content type
131 String accepts = request.getHeader("Accept");
132 String userAgent = request.getHeader("User-Agent");
133 if (WebloggerRuntimeConfig.getBooleanProperty("site.newsfeeds.styledFeeds") &&
134 accepts != null && accepts.indexOf("*/*") != -1 &&
135 userAgent != null && userAgent.startsWith("Mozilla")) {
136 // client is a browser and feed style is enabled so we want
137 // browsers to load the page rather than popping up the download
138 // dialog, so we provide a content-type that browsers will display
139 response.setContentType("text/xml");
140 } else if("rss".equals(feedRequest.getFormat())) {
141 response.setContentType("application/rss+xml; charset=utf-8");
142 } else if("atom".equals(feedRequest.getFormat())) {
143 response.setContentType("application/atom+xml; charset=utf-8");
144 }
145
146 // generate cache key
147 String cacheKey = null;
148 if(isSiteWide) {
149 cacheKey = siteWideCache.generateKey(feedRequest);
150 } else {
151 cacheKey = weblogFeedCache.generateKey(feedRequest);
152 }
153
154 // cached content checking
155 CachedContent cachedContent = null;
156 if(isSiteWide) {
157 cachedContent = (CachedContent) siteWideCache.get(cacheKey);
158 } else {
159 cachedContent = (CachedContent) weblogFeedCache.get(cacheKey, lastModified);
160 }
161
162 if(cachedContent != null) {
163 log.debug("HIT "+cacheKey);
164
165 response.setContentLength(cachedContent.getContent().length);
166 response.getOutputStream().write(cachedContent.getContent());
167 return;
168
169 } else {
170 log.debug("MISS "+cacheKey);
171 }
172
173
174 // validation. make sure that request input makes sense.
175 boolean invalid = false;
176 if(feedRequest.getLocale() != null) {
177
178 // locale view only allowed if weblog has enabled it
179 if(!feedRequest.getWeblog().isEnableMultiLang()) {
180 invalid = true;
181 }
182
183 }
184 if(feedRequest.getWeblogCategoryName() != null) {
185
186 // category specified. category must exist.
187 if(feedRequest.getWeblogCategory() == null) {
188 invalid = true;
189 }
190
191 } else if(feedRequest.getTags() != null && feedRequest.getTags().size() > 0) {
192
193 try {
194 // tags specified. make sure they exist.
195 WeblogManager wmgr = WebloggerFactory.getWeblogger().getWeblogManager();
196 invalid = !wmgr.getTagComboExists(feedRequest.getTags(), (isSiteWide) ? null : weblog);
197 } catch (WebloggerException ex) {
198 invalid = true;
199 }
200 }
201
202 if(invalid) {
203 if(!response.isCommitted()) response.reset();
204 response.sendError(HttpServletResponse.SC_NOT_FOUND);
205 return;
206 }
207
208
209 // do we need to force a specific locale for the request?
210 if(feedRequest.getLocale() == null && !weblog.isShowAllLangs()) {
211 feedRequest.setLocale(weblog.getLocale());
212 }
213
214 // looks like we need to render content
215 HashMap model = new HashMap();
216 String pageId = null;
217 try {
218 // determine what template to render with
219 if (WebloggerRuntimeConfig.isSiteWideWeblog(weblog.getHandle())) {
220 pageId = "templates/feeds/site-"+feedRequest.getType()+"-"+feedRequest.getFormat()+".vm";
221 } else {
222 pageId = "templates/feeds/weblog-"+feedRequest.getType()+"-"+feedRequest.getFormat()+".vm";
223 }
224
225 // populate the rendering model
226 Map initData = new HashMap();
227 initData.put("parsedRequest", feedRequest);
228
229 // define url strategy
230 initData.put("urlStrategy", WebloggerFactory.getWeblogger().getUrlStrategy());
231
232 // Load models for feeds
233 String feedModels = WebloggerConfig.getProperty("rendering.feedModels");
234 ModelLoader.loadModels(feedModels, model, initData, true);
235
236 // Load special models for site-wide blog
237
238 if(WebloggerRuntimeConfig.isSiteWideWeblog(weblog.getHandle())) {
239 String siteModels = WebloggerConfig.getProperty("rendering.siteModels");
240 ModelLoader.loadModels(siteModels, model, initData, true);
241 }
242
243 // Load weblog custom models
244 ModelLoader.loadCustomModels(weblog, model, initData);
245
246 if("entries".equals(feedRequest.getType()) && feedRequest.getTerm() != null) {
247 pageId = "templates/feeds/weblog-search-atom.vm";
248 ModelLoader.loadModels(SearchResultsFeedModel.class.getName(), model, initData, true);
249 }
250
251 } catch (WebloggerException ex) {
252 log.error("ERROR loading model for page", ex);
253
254 if(!response.isCommitted()) response.reset();
255 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
256 return;
257 }
258
259
260 // lookup Renderer we are going to use
261 Renderer renderer = null;
262 try {
263 log.debug("Looking up renderer");
264 Template template = new StaticTemplate(pageId, "velocity");
265 renderer = RendererManager.getRenderer(template);
266 } catch(Exception e) {
267 // nobody wants to render my content :(
268
269 // TODO: this log message has been disabled because it fills up
270 // the logs with useless errors due to the fact that the way these
271 // template ids are formed comes directly from the request and it
272 // often gets bunk data causing invalid template ids.
273 // at some point we should have better validation on the input so
274 // that we can quickly dispatch invalid feed requests and only
275 // get this far if we expect the template to be found
276 //log.error("Couldn't find renderer for page "+pageId, e);
277
278 if(!response.isCommitted()) response.reset();
279 response.sendError(HttpServletResponse.SC_NOT_FOUND);
280 return;
281 }
282
283 // render content. use default size of about 24K for a standard page
284 CachedContent rendererOutput = new CachedContent(24567);
285 try {
286 log.debug("Doing rendering");
287 renderer.render(model, rendererOutput.getCachedWriter());
288
289 // flush rendered output and close
290 rendererOutput.flush();
291 rendererOutput.close();
292 } catch(Exception e) {
293 // bummer, error during rendering
294 log.error("Error during rendering for page "+pageId, e);
295
296 if(!response.isCommitted()) response.reset();
297 response.sendError(HttpServletResponse.SC_NOT_FOUND);
298 return;
299 }
300
301
302 // post rendering process
303
304 // flush rendered content to response
305 log.debug("Flushing response output");
+ 306 response.setContentLength(rendererOutput.getContent().length);
307 response.getOutputStream().write(rendererOutput.getContent());
308
309 // cache rendered content. only cache if user is not logged in?
310 log.debug("PUT "+cacheKey);
311 if(isSiteWide) {
312 siteWideCache.put(cacheKey, rendererOutput);
313 } else {
314 weblogFeedCache.put(cacheKey, rendererOutput);
315 }
316
317 log.debug("Exiting");
318 }
319
320 }
SofCheck Inspector Build Version : 2.18479
| FeedServlet.java |
2009-Jan-02 14:24:44 |
| FeedServlet.class |
2009-Sep-04 03:12:45 |