KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > roller > ui > rendering > servlets > PageServlet


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.ui.rendering.servlets;
20
21 import java.io.IOException JavaDoc;
22 import java.util.Date JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.regex.Pattern JavaDoc;
26 import javax.servlet.ServletConfig JavaDoc;
27 import javax.servlet.ServletException JavaDoc;
28 import javax.servlet.http.HttpServlet JavaDoc;
29 import javax.servlet.http.HttpServletRequest JavaDoc;
30 import javax.servlet.http.HttpServletResponse JavaDoc;
31 import javax.servlet.jsp.JspFactory JavaDoc;
32 import javax.servlet.jsp.PageContext JavaDoc;
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.apache.roller.RollerException;
36 import org.apache.roller.business.referrers.IncomingReferrer;
37 import org.apache.roller.business.referrers.ReferrerQueueManager;
38 import org.apache.roller.config.RollerConfig;
39 import org.apache.roller.config.RollerRuntimeConfig;
40 import org.apache.roller.model.RollerFactory;
41 import org.apache.roller.pojos.Template;
42 import org.apache.roller.pojos.WeblogTemplate;
43 import org.apache.roller.pojos.WebsiteData;
44 import org.apache.roller.ui.core.RollerContext;
45 import org.apache.roller.ui.rendering.util.InvalidRequestException;
46 import org.apache.roller.ui.rendering.util.WeblogPageRequest;
47 import org.apache.roller.util.cache.CachedContent;
48 import org.apache.roller.ui.rendering.Renderer;
49 import org.apache.roller.ui.rendering.RendererManager;
50 import org.apache.roller.ui.rendering.model.ModelLoader;
51 import org.apache.roller.ui.rendering.util.SiteWideCache;
52 import org.apache.roller.ui.rendering.util.WeblogEntryCommentForm;
53 import org.apache.roller.ui.rendering.util.WeblogPageCache;
54 import org.apache.roller.ui.rendering.util.ModDateHeaderUtil;
55 import org.apache.roller.util.SpamChecker;
56
57
58 /**
59  * Provides access to weblog pages.
60  *
61  * @web.servlet name="PageServlet" load-on-startup="5"
62  * @web.servlet-mapping url-pattern="/roller-ui/rendering/page/*"
63  */

64 public class PageServlet extends HttpServlet JavaDoc {
65     
66     private static Log log = LogFactory.getLog(PageServlet.class);
67     
68     // for referrer processing
69
private boolean processReferrers = true;
70     private static Pattern JavaDoc robotPattern = null;
71     
72     // for caching
73
private boolean excludeOwnerPages = false;
74     private WeblogPageCache weblogPageCache = null;
75     private SiteWideCache siteWideCache = null;
76     
77     
78     /**
79      * Init method for this servlet
80      */

81     public void init(ServletConfig JavaDoc servletConfig) throws ServletException JavaDoc {
82         
83         super.init(servletConfig);
84         
85         log.info("Initializing PageServlet");
86         
87         this.excludeOwnerPages =
88                 RollerConfig.getBooleanProperty("cache.excludeOwnerEditPages");
89         
90         // get a reference to the weblog page cache
91
this.weblogPageCache = WeblogPageCache.getInstance();
92         
93         // get a reference to the site wide cache
94
this.siteWideCache = SiteWideCache.getInstance();
95         
96         // see if built-in referrer processing is enabled
97
this.processReferrers =
98                 RollerConfig.getBooleanProperty("referrers.processing.enabled");
99         
100         log.info("Referrer processing enabled = "+this.processReferrers);
101         
102         // check for possible robot pattern
103
String JavaDoc robotPatternStr = RollerConfig.getProperty("referrer.robotCheck.userAgentPattern");
104         if (robotPatternStr != null && robotPatternStr.length() > 0) {
105             // Parse the pattern, and store the compiled form.
106
try {
107                 robotPattern = Pattern.compile(robotPatternStr);
108             } catch (Exception JavaDoc e) {
109                 // Most likely a PatternSyntaxException; log and continue as if it is not set.
110
log.error("Error parsing referrer.robotCheck.userAgentPattern value '" +
111                         robotPatternStr + "'. Robots will not be filtered. ", e);
112             }
113         }
114     }
115     
116     
117     /**
118      * Handle GET requests for weblog pages.
119      */

120     public void doGet(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
121             throws ServletException JavaDoc, IOException JavaDoc {
122         
123         log.debug("Entering");
124         
125         // do referrer processing, if it's enabled
126
// NOTE: this *must* be done first because it triggers a hibernate flush
127
// which will close the active session and cause lazy init exceptions otherwise
128
if(this.processReferrers) {
129             boolean spam = this.processReferrer(request);
130             if(spam) {
131                 log.debug("spammer, giving 'em a 403");
132                 if(!response.isCommitted()) response.reset();
133                 response.sendError(HttpServletResponse.SC_FORBIDDEN);
134                 return;
135             }
136         }
137         
138         
139         WebsiteData weblog = null;
140         boolean isSiteWide = false;
141         
142         WeblogPageRequest pageRequest = null;
143         try {
144             pageRequest = new WeblogPageRequest(request);
145             
146             weblog = pageRequest.getWeblog();
147             if(weblog == null) {
148                 throw new RollerException("unable to lookup weblog: "+
149                         pageRequest.getWeblogHandle());
150             }
151             
152             // is this the site-wide weblog?
153
isSiteWide = RollerRuntimeConfig.isSiteWideWeblog(pageRequest.getWeblogHandle());
154             
155         } catch (Exception JavaDoc e) {
156             // some kind of error parsing the request or looking up weblog
157
log.debug("error creating page request", e);
158             response.sendError(HttpServletResponse.SC_NOT_FOUND);
159             return;
160         }
161         
162         
163         // determine the lastModified date for this content
164
long lastModified = System.currentTimeMillis();
165         if(isSiteWide) {
166             lastModified = siteWideCache.getLastModified().getTime();
167         } else if (weblog.getLastModified() != null) {
168             lastModified = weblog.getLastModified().getTime();
169         }
170
171         // 304 Not Modified handling.
172
// We skip this for logged in users to avoid the scenerio where a user
173
// views their weblog, logs in, then gets a 304 without the 'edit' links
174
if(!pageRequest.isLoggedIn()) {
175             if (ModDateHeaderUtil.respondIfNotModified(request,response,lastModified)) {
176                 return;
177             } else {
178                 // set last-modified date
179
ModDateHeaderUtil.setLastModifiedHeader(response,lastModified);
180             }
181         }
182
183                 
184         // generate cache key
185
String JavaDoc cacheKey = null;
186         if(isSiteWide) {
187             cacheKey = siteWideCache.generateKey(pageRequest);
188         } else {
189             cacheKey = weblogPageCache.generateKey(pageRequest);
190         }
191         
192         // cached content checking
193
if((!this.excludeOwnerPages || !pageRequest.isLoggedIn()) &&
194                 request.getAttribute("skipCache") == null) {
195             
196             CachedContent cachedContent = null;
197             if(isSiteWide) {
198                 cachedContent = (CachedContent) siteWideCache.get(cacheKey);
199             } else {
200                 cachedContent = (CachedContent) weblogPageCache.get(cacheKey, lastModified);
201             }
202             
203             if(cachedContent != null) {
204                 log.debug("HIT "+cacheKey);
205                 
206                 response.setContentLength(cachedContent.getContent().length);
207                 response.setContentType(cachedContent.getContentType());
208                 response.getOutputStream().write(cachedContent.getContent());
209                 return;
210                 
211             } else {
212                 log.debug("MISS "+cacheKey);
213             }
214         }
215
216         
217         // figure out what we are going to render
218
Template page = null;
219         
220         // If this is a popup request, then deal with it specially
221
// TODO: do we really need to keep supporting this?
222
if (request.getParameter("popup") != null) {
223             try {
224                 // Does user have a popupcomments page?
225
page = weblog.getPageByName("_popupcomments");
226             } catch(Exception JavaDoc e ) {
227                 // ignored ... considered page not found
228
}
229             
230             // User doesn't have one so return the default
231
if(page == null) {
232                 page = new WeblogTemplate("templates/weblog/popupcomments.vm", weblog,
233                         "Comments", "Comments", "dummy_link",
234                         "dummy_template", new Date JavaDoc(), "velocity", true, false, null);
235             }
236             
237         // If request specified the page, then go with that
238
} else if (pageRequest.getWeblogPageName() != null) {
239             page = pageRequest.getWeblogPage();
240             
241         // If page not available from request, then use weblog's default
242
} else {
243             try {
244                 page = weblog.getDefaultPage();
245             } catch(Exception JavaDoc e) {
246                 log.error("Error getting weblogs default page", e);
247             }
248         }
249         
250         // Still no page? Then that is a 404
251
if (page == null) {
252             if(!response.isCommitted()) response.reset();
253             response.sendError(HttpServletResponse.SC_NOT_FOUND);
254             return;
255         }
256         
257         log.debug("page found, dealing with it");
258         
259         // validation
260
boolean invalid = false;
261         if(pageRequest.getWeblogPageName() != null && page.isHidden()) {
262             invalid = true;
263         }
264         if(pageRequest.getLocale() != null) {
265             
266             // locale view only allowed if weblog has enabled it
267
if(!pageRequest.getWeblog().isEnableMultiLang()) {
268                 invalid = true;
269             }
270             
271         }
272         if(pageRequest.getWeblogAnchor() != null) {
273             
274             // permalink specified. entry must exist and locale must match
275
if(pageRequest.getWeblogEntry() == null) {
276                 invalid = true;
277             } else if (pageRequest.getLocale() != null &&
278                     !pageRequest.getWeblogEntry().getLocale().startsWith(pageRequest.getLocale())) {
279                 invalid = true;
280             }
281             
282         } else if(pageRequest.getWeblogCategoryName() != null) {
283             
284             // category specified. category must exist.
285
if(pageRequest.getWeblogCategory() == null) {
286                 invalid = true;
287             }
288         }
289        
290         
291         if(invalid) {
292             if(!response.isCommitted()) response.reset();
293             response.sendError(HttpServletResponse.SC_NOT_FOUND);
294             return;
295         }
296         
297         
298         // looks like we need to render content
299

300         // set the content type
301
String JavaDoc mimeType = RollerContext.getServletContext().getMimeType(page.getLink());
302         String JavaDoc contentType = "text/html; charset=utf-8";
303         if(mimeType != null) {
304             // we found a match ... set the content type
305
contentType = mimeType+"; charset=utf-8";
306         }
307
308         HashMap JavaDoc model = new HashMap JavaDoc();
309         try {
310             PageContext JavaDoc pageContext = JspFactory.getDefaultFactory().getPageContext(
311                     this, request, response,"", true, 8192, true);
312             
313             // special hack for menu tag
314
request.setAttribute("pageRequest", pageRequest);
315             
316             // populate the rendering model
317
Map JavaDoc initData = new HashMap JavaDoc();
318             initData.put("request", request);
319             initData.put("requestParameters", request.getParameterMap());
320             initData.put("weblogRequest", pageRequest);
321             initData.put("pageContext", pageContext);
322             
323             // if this was a comment posting, check for comment form
324
WeblogEntryCommentForm commentForm =
325                     (WeblogEntryCommentForm) request.getAttribute("commentForm");
326             if(commentForm != null) {
327                 initData.put("commentForm", commentForm);
328             }
329             
330             // Load models for pages
331
String JavaDoc pageModels = RollerConfig.getProperty("rendering.pageModels");
332             ModelLoader.loadModels(pageModels, model, initData, true);
333             
334             // Load special models for site-wide blog
335
if(RollerRuntimeConfig.isSiteWideWeblog(weblog.getHandle())) {
336                 String JavaDoc siteModels = RollerConfig.getProperty("rendering.siteModels");
337                 ModelLoader.loadModels(siteModels, model, initData, true);
338             }
339
340             // Load weblog custom models
341
ModelLoader.loadCustomModels(weblog, model, initData);
342             
343             // ick, gotta load pre-3.0 model stuff as well :(
344
ModelLoader.loadOldModels(model, request, response, pageContext, pageRequest);
345             
346         } catch (RollerException ex) {
347             log.error("Error loading model objects for page", ex);
348             
349             if(!response.isCommitted()) response.reset();
350             response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
351             return;
352         }
353         
354         
355         // lookup Renderer we are going to use
356
Renderer renderer = null;
357         try {
358             log.debug("Looking up renderer");
359             renderer = RendererManager.getRenderer(page);
360         } catch(Exception JavaDoc e) {
361             // nobody wants to render my content :(
362
log.error("Couldn't find renderer for page "+page.getId(), e);
363             
364             if(!response.isCommitted()) response.reset();
365             response.sendError(HttpServletResponse.SC_NOT_FOUND);
366             return;
367         }
368         
369         // render content. use size of about 24K for a standard page
370
CachedContent rendererOutput = new CachedContent(24567, contentType);
371         try {
372             log.debug("Doing rendering");
373             renderer.render(model, rendererOutput.getCachedWriter());
374             
375             // flush rendered output and close
376
rendererOutput.flush();
377             rendererOutput.close();
378         } catch(Exception JavaDoc e) {
379             // bummer, error during rendering
380
log.error("Error during rendering for page "+page.getId(), e);
381             
382             if(!response.isCommitted()) response.reset();
383             response.sendError(HttpServletResponse.SC_NOT_FOUND);
384             return;
385         }
386         
387         
388         // post rendering process
389

390         // flush rendered content to response
391
log.debug("Flushing response output");
392         response.setContentType(contentType);
393         response.setContentLength(rendererOutput.getContent().length);
394         response.getOutputStream().write(rendererOutput.getContent());
395         
396         // cache rendered content. only cache if user is not logged in?
397
if((!this.excludeOwnerPages || !pageRequest.isLoggedIn()) &&
398                 request.getAttribute("skipCache") == null) {
399             log.debug("PUT "+cacheKey);
400             
401             // put it in the right cache
402
if(isSiteWide) {
403                 siteWideCache.put(cacheKey, rendererOutput);
404             } else {
405                 weblogPageCache.put(cacheKey, rendererOutput);
406             }
407         } else {
408             log.debug("SKIPPED "+cacheKey);
409         }
410         
411         log.debug("Exiting");
412     }
413         
414     
415     /**
416      * Handle POST requests.
417      *
418      * We have this here because the comment servlet actually forwards some of
419      * its requests on to us to render some pages with cusom messaging. We
420      * may want to revisit this approach in the future and see if we can do
421      * this in a different way, but for now this is the easy way.
422      */

423     public void doPost(HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response)
424             throws ServletException JavaDoc, IOException JavaDoc {
425         
426         // make sure caching is disabled
427
request.setAttribute("skipCache", "true");
428         
429         // handle just like a GET request
430
this.doGet(request, response);
431     }
432     
433     
434     /**
435      * Process the incoming request to extract referrer info and pass it on
436      * to the referrer processing queue for tracking.
437      *
438      * @returns true if referrer was spam, false otherwise
439      */

440     private boolean processReferrer(HttpServletRequest JavaDoc request) {
441         
442         log.debug("processing referrer for "+request.getRequestURI());
443         
444         // bleh! because ref processing does a flush it will close
445
// our hibernate session and cause lazy init exceptions on
446
// objects we have fetched, so we need to use a separate
447
// page request object for this
448
WeblogPageRequest pageRequest;
449         try {
450             pageRequest = new WeblogPageRequest(request);
451         } catch (InvalidRequestException ex) {
452             return false;
453         }
454         
455         // if this came from site-wide frontpage then skip it
456
if(RollerRuntimeConfig.isSiteWideWeblog(pageRequest.getWeblogHandle())) {
457             return false;
458         }
459         
460         // if this came from a robot then don't process it
461
if (robotPattern != null) {
462             String JavaDoc userAgent = request.getHeader("User-Agent");
463             if (userAgent != null && userAgent.length() > 0 &&
464                     robotPattern.matcher(userAgent).matches()) {
465                 log.debug("skipping referrer from robot");
466                 return false;
467             }
468         }
469         
470         String JavaDoc referrerUrl = request.getHeader("Referer");
471         StringBuffer JavaDoc reqsb = request.getRequestURL();
472         if (request.getQueryString() != null) {
473             reqsb.append("?");
474             reqsb.append(request.getQueryString());
475         }
476         String JavaDoc requestUrl = reqsb.toString();
477         
478         log.debug("referrer = "+referrerUrl);
479         
480         // if this came from persons own blog then don't process it
481
String JavaDoc selfSiteFragment = "/"+pageRequest.getWeblogHandle();
482         if (referrerUrl != null && referrerUrl.indexOf(selfSiteFragment) != -1) {
483             log.debug("skipping referrer from own blog");
484             return false;
485         }
486         
487         // validate the referrer
488
if (pageRequest != null && pageRequest.getWeblogHandle() != null) {
489             
490             // Base page URLs, with and without www.
491
String JavaDoc basePageUrlWWW =
492                     RollerRuntimeConfig.getAbsoluteContextURL() + "/" + pageRequest.getWeblogHandle();
493             String JavaDoc basePageUrl = basePageUrlWWW;
494             if ( basePageUrlWWW.startsWith("http://www.") ) {
495                 // chop off the http://www.
496
basePageUrl = "http://"+basePageUrlWWW.substring(11);
497             }
498             
499             // ignore referrers coming from users own blog
500
if (referrerUrl == null ||
501                     (!referrerUrl.startsWith(basePageUrl) &&
502                     !referrerUrl.startsWith(basePageUrlWWW))) {
503                 
504                 // validate the referrer
505
if ( referrerUrl != null ) {
506                     // treat editor referral as direct
507
int lastSlash = requestUrl.indexOf("/", 8);
508                     if (lastSlash == -1) lastSlash = requestUrl.length();
509                     String JavaDoc requestSite = requestUrl.substring(0, lastSlash);
510                     
511                     if (referrerUrl.matches(requestSite + ".*\\.do.*")) {
512                         referrerUrl = null;
513                     } else if(SpamChecker.checkReferrer(pageRequest.getWeblog(), referrerUrl)) {
514                         return true;
515                     }
516                 }
517
518             } else {
519                 log.debug("Ignoring referer = "+referrerUrl);
520                 return false;
521             }
522         }
523         
524         // referrer is valid, lets record it
525
try {
526             IncomingReferrer referrer = new IncomingReferrer();
527             referrer.setReferrerUrl(referrerUrl);
528             referrer.setRequestUrl(requestUrl);
529             referrer.setWeblogHandle(pageRequest.getWeblogHandle());
530             referrer.setWeblogAnchor(pageRequest.getWeblogAnchor());
531             referrer.setWeblogDateString(pageRequest.getWeblogDate());
532             
533             ReferrerQueueManager refQueue =
534                     RollerFactory.getRoller().getReferrerQueueManager();
535             refQueue.processReferrer(referrer);
536         } catch(Exception JavaDoc e) {
537             log.error("Error processing referrer", e);
538         }
539         
540         return false;
541     }
542     
543 }
544
Popular Tags