001: /*
002: * Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
003: *
004: * Project: OpenChronicle
005: *
006: * $Id: BlogNavigator.java,v 1.4 2007/02/20 03:54:31 bastafidli Exp $
007: *
008: * This program is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU General Public License as published by
010: * the Free Software Foundation; version 2 of the License.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021:
022: package org.opensubsystems.blog.www;
023:
024: import java.util.logging.Level;
025: import java.util.logging.Logger;
026:
027: import javax.servlet.http.HttpServletRequest;
028:
029: import org.opensubsystems.blog.data.Blog;
030: import org.opensubsystems.blog.data.Entry;
031: import org.opensubsystems.core.util.Log;
032: import org.opensubsystems.core.www.WebCommonConstants;
033: import org.opensubsystems.core.www.WebUtils;
034: import org.opensubsystems.patterns.listdata.data.ListOptions;
035: import org.opensubsystems.patterns.listdata.www.ListBrowserServlet;
036:
037: /**
038: * Class responsible for parsing and creating URLs for blogs and their entries.
039: *
040: * If root URL is http://www.opensubsystems.org then the structure of URLs is
041: * - Bog with folder "firstblog"
042: * root URL = http://www.opensubsystems.org/firstblog/
043: * page URL = http://www.opensubsystems.org/firstblog/index.html
044: * - Entry belonging to "firstblog" with ID 123456789
045: * page URL = http://www.opensubsystems.org/firstblog/123456789.html
046: *
047: * @version $Id: BlogNavigator.java,v 1.4 2007/02/20 03:54:31 bastafidli Exp $
048: * @author Miro Halas
049: * @code.reviewer Miro Halas
050: * @code.reviewed 1.3 2006/07/15 09:09:26 bastafidli
051: */
052: public class BlogNavigator {
053: // Constants ////////////////////////////////////////////////////////////////
054:
055: /**
056: * Page where user can login to the system.
057: */
058: public static final String LOGIN_WEB_PAGE = "login.html";
059:
060: /**
061: * Page where user can logout to the system.
062: */
063: public static final String LOGOUT_WEB_PAGE = "logout.html";
064:
065: /**
066: * Default name stem to use when constructing
067: */
068: public static final String PAGED_ACCESS_WEB_PAGE = "page";
069:
070: // Attributes ///////////////////////////////////////////////////////////////
071:
072: /**
073: * URL to the directory containing all blogs.
074: */
075: protected String m_strBlogDirectoryURL;
076:
077: /**
078: * Request that will be used by this navigator
079: */
080: protected HttpServletRequest m_hsrqRequest;
081:
082: // Cached values ////////////////////////////////////////////////////////////
083:
084: /**
085: * Logger for this class
086: */
087: private static Logger s_logger = Log
088: .getInstance(BlogNavigator.class);
089:
090: // Constructors /////////////////////////////////////////////////////////////
091:
092: /**
093: * Creates a new instance of BlogNavigator
094: *
095: * @param hsrqRequest - request that will be used by this navigator
096: */
097: public BlogNavigator(HttpServletRequest hsrqRequest) {
098: m_hsrqRequest = hsrqRequest;
099:
100: // If this is part of web application installed under name chronicle
101: // and this servlet is registered under name blog, the navigator
102: // will be constructed for directory /chronicle/blog
103: String strBlogDirectoryURL = hsrqRequest.getContextPath();
104:
105: if (!strBlogDirectoryURL
106: .endsWith(WebCommonConstants.URL_SEPARATOR)) {
107: // Be forgiving and correct the URL if it is not correct, but print
108: // message about it so we can optimize code
109: s_logger
110: .finest("Optimize call to BlogNavigator constructor"
111: + " to pass fully formed URL.");
112:
113: StringBuffer sbTemp = new StringBuffer(strBlogDirectoryURL);
114: sbTemp.append(WebCommonConstants.URL_SEPARATOR);
115: m_strBlogDirectoryURL = sbTemp.toString();
116: } else {
117: m_strBlogDirectoryURL = strBlogDirectoryURL;
118: }
119: }
120:
121: // URL Accessors ////////////////////////////////////////////////////////////
122:
123: /**
124: * Flag signaling if the navigator creates dynamic URLS (e.g. URLS with ?
125: * and &) or it creates URLs that ressemble static pages
126: * (e.g. http://www.bastafidli.com/myblog/page7.html)
127: *
128: * @return boolean
129: */
130: public boolean getIsDynamic() {
131: return false;
132: }
133:
134: /**
135: * Get URL to where a form can be posted to be processed
136: *
137: * @return String - URL to posts the forms to
138: */
139: public String getPostURL() {
140: // For static navigation the URL will be posted to the same servlet where
141: // it came from
142: return "";
143: }
144:
145: /**
146: * Get URL to the root directory where all blogs exist.
147: *
148: * @return String - URL ends with WebCommonConstants.URL_SEPARATOR_CHAR
149: */
150: public String getRootURL() {
151: StringBuffer sbURL = new StringBuffer(m_strBlogDirectoryURL);
152:
153: sbURL.append(WebCommonConstants.DEFAULT_DIRECTORY_WEB_PAGE);
154: return sbURL.toString();
155: }
156:
157: /**
158: * Get URL to the page which displays this blog.
159: *
160: * @param blog - blog to get page URL for
161: * @return String
162: */
163: public String getURL(Blog blog) {
164: return getBlogURL(blog.getFolder());
165: }
166:
167: /**
168: * Get URL to the page that displays specified blog.
169: *
170: * @param objBlogIdentification - identification of the blog to get page URL
171: * for, which should be the folder
172: * @return String
173: */
174: public String getBlogURL(Object objBlogIdentification) {
175: StringBuffer sbURL;
176:
177: sbURL = getBlogRootURL(objBlogIdentification.toString());
178: sbURL.append(WebCommonConstants.DEFAULT_DIRECTORY_WEB_PAGE);
179:
180: return sbURL.toString();
181: }
182:
183: /**
184: * Get URL to the page which displays specified entry.
185: *
186: * @param blog - blog to which this entry belongs to
187: * @param entry - entry to get page URL for
188: * @return String - URL to the page displaying specified entry
189: */
190: public String getURL(Blog blog, Entry entry) {
191: return getBlogEntryURL(blog.getFolder(), entry.getId());
192: }
193:
194: /**
195: * Get URL to the page which displays specified entry without knowing
196: * details of the blog the entry belongs to
197: *
198: * @param entry - entry to get page URL for
199: * @return String - URL to the page displaying specified entry
200: */
201: public String getURL(Entry entry) {
202: StringBuffer sbURL = new StringBuffer("blog");
203:
204: sbURL.append(entry.getParentId());
205: return getBlogEntryURL(sbURL.toString(), entry.getId());
206: }
207:
208: /**
209: * Get URL to the page which displays specified blog entry.
210: *
211: * @param entryIdentification - identification of entry
212: * @return String - URL to the page displaying specified entry
213: */
214: public String getURL(BlogEntryIdentification entryIdentification) {
215: return getBlogEntryURL(
216: (String) entryIdentification.m_objBlogIdentification,
217: entryIdentification.m_iBlogEntryIdentification);
218: }
219:
220: /**
221: * Get blog which coresponds to given request.
222: *
223: * @param hsrqRequest - the servlet request.
224: * @return Object - Identification of Blog coresponding to given request.
225: * This can be either String value identifying the Blog
226: * folder or Integer value identifying the Blog URL.
227: * Ff no such Blog exists, an exception will be thrown
228: */
229: public Object getBlogIdentification(HttpServletRequest hsrqRequest) {
230: // Static BlogNavigator always returnes string value since it is part of
231: // the URL
232: String strBlogId = "";
233: String strExtraPath;
234: String strURL;
235:
236: strURL = hsrqRequest.getServletPath();
237: strExtraPath = hsrqRequest.getPathInfo();
238: if (strExtraPath != null) {
239: strURL += strExtraPath;
240: }
241: if ((strURL != null) && (strURL.length() > 0)) {
242: int iIndex = strURL
243: .indexOf(WebCommonConstants.URL_SEPARATOR_CHAR);
244: int iLastIndex = strURL
245: .lastIndexOf(WebCommonConstants.URL_SEPARATOR_CHAR);
246: if ((iLastIndex != -1) && (iLastIndex > iIndex)) {
247: // Get blog which has ID the same as the path specified in the URL
248: strBlogId = strURL.substring(iIndex + 1, iLastIndex);
249: }
250: }
251:
252: return strBlogId;
253: }
254:
255: /**
256: * Get blog and entries which coresponds to given request.
257: *
258: * @param hsrqRequest - the servlet request.
259: * @return BlogEntryIdentification
260: */
261: public BlogEntryIdentification getBlogEntryIdentification(
262: HttpServletRequest hsrqRequest) {
263: String strBlogURL;
264: String strExtraPath;
265: BlogEntryIdentification entryIdentification = null;
266:
267: strBlogURL = hsrqRequest.getServletPath();
268: strExtraPath = hsrqRequest.getPathInfo();
269: if (strExtraPath != null) {
270: strBlogURL += strExtraPath;
271: }
272: if ((strBlogURL != null) && (strBlogURL.length() > 0)) {
273: int iIndex = strBlogURL
274: .indexOf(WebCommonConstants.URL_SEPARATOR_CHAR);
275: int iLastIndex = strBlogURL
276: .lastIndexOf(WebCommonConstants.URL_SEPARATOR_CHAR);
277:
278: if ((iLastIndex != -1) && (iLastIndex > iIndex)) {
279: try {
280: int iEntryId;
281:
282: iEntryId = Integer
283: .parseInt(strBlogURL
284: .substring(
285: iLastIndex + 1,
286: strBlogURL
287: .lastIndexOf(WebCommonConstants.WEB_PAGE_EXTENSION)));
288: entryIdentification = new BlogEntryIdentification();
289: entryIdentification.m_objBlogIdentification = strBlogURL
290: .substring(
291: strBlogURL
292: .indexOf(WebCommonConstants.URL_SEPARATOR_CHAR) + 1,
293: iLastIndex);
294: entryIdentification.m_iBlogEntryIdentification = iEntryId;
295:
296: } catch (NumberFormatException nfeExc) {
297: s_logger
298: .log(
299: Level.FINEST,
300: "The URL doesn't identify valid Blog entry.",
301: nfeExc);
302: // Just return null and let the caller handle it
303: }
304: }
305: }
306:
307: return entryIdentification;
308: }
309:
310: /**
311: * Test if the given request is a request for data displayed on an index page
312: * which is page identified either as index.html or as pageXYZ.html where XYZ
313: * is a number
314: *
315: * @return int - if the request identifies a valid index page then the page
316: * number (a positive value) is returned otherwise a negative
317: * value is returned.
318: */
319: public int isIndexPage() {
320: int iPageNumber = -1;
321: boolean bReturn;
322:
323: bReturn = WebUtils.isIndexPage(m_hsrqRequest);
324: if (!bReturn) {
325: // URL which ends with pageXYZ.html where XYZ is a number is considered
326: // to be an index page for a list of data items
327: String strPath;
328:
329: strPath = WebUtils.getFullRequestPath(m_hsrqRequest);
330: if (strPath.endsWith(WebCommonConstants.WEB_PAGE_EXTENSION)) {
331: int iIndex;
332:
333: iIndex = strPath
334: .lastIndexOf(WebCommonConstants.URL_SEPARATOR);
335: if (iIndex != -1) {
336: // Extract the page number without extension
337: strPath = strPath.substring(iIndex + 1, strPath
338: .length()
339: - WebCommonConstants.WEB_PAGE_EXTENSION
340: .length());
341: if (strPath.startsWith(PAGED_ACCESS_WEB_PAGE)) {
342: strPath = strPath
343: .substring(PAGED_ACCESS_WEB_PAGE
344: .length());
345: try {
346: iPageNumber = Integer.parseInt(strPath);
347: if (iPageNumber <= 0) {
348: // This is not a valid page number
349: iPageNumber = -1;
350: }
351: } catch (NumberFormatException nfeExc) {
352: // This is not an index page
353: }
354: }
355: }
356: }
357: } else {
358: // The main index page is the first page
359: iPageNumber = 1;
360: }
361:
362: return iPageNumber;
363: }
364:
365: /**
366: * Test if specified request identifies path to a blog index page. It either
367: * doesn't contain any path e.g. http://www.bastafidli.com or just a root
368: * directory http://www.bastafidli.com/ with some index page already tested
369: * by isIndexPage.
370: *
371: * @return boolean - true if the page is index page for blogs
372: */
373: public boolean isBlogIndexPage() {
374: String strPath;
375: int iFirstIndex = -1;
376: int iLastIndex = -1;
377:
378: strPath = WebUtils.getFullRequestPath(m_hsrqRequest);
379:
380: // If there are two folder separators, the request is for the subindex
381: // page, otherwise it is for the main index page
382: iFirstIndex = strPath
383: .indexOf(WebCommonConstants.URL_SEPARATOR_CHAR);
384: if (iFirstIndex == 0) {
385: iLastIndex = strPath
386: .lastIndexOf(WebCommonConstants.URL_SEPARATOR_CHAR);
387: }
388:
389: // If there is no / both values will be -1
390: // there is only one or none /
391: return (iFirstIndex == iLastIndex)
392: // there is no /
393: && ((iFirstIndex == -1)
394: // there is one / and it is the last
395: || (strPath.endsWith(WebCommonConstants.URL_SEPARATOR)
396: // or it ends with .html
397: || strPath
398: .endsWith(WebCommonConstants.WEB_PAGE_EXTENSION)));
399: }
400:
401: /**
402: * Test if the requested path is path to the page where user can login to
403: * the system.
404: *
405: * @return boolean - true if the page is login page
406: */
407: public boolean isLoginPage() {
408: String strPath;
409:
410: strPath = WebUtils.getFullRequestPath(m_hsrqRequest);
411:
412: return strPath.endsWith(LOGIN_WEB_PAGE);
413: }
414:
415: /**
416: * Test if the requested path is path to the page where user can login to
417: * the system.
418: *
419: * @return boolean - true if the page is login page
420: */
421: public boolean isLogoutPage() {
422: String strPath;
423:
424: strPath = WebUtils.getFullRequestPath(m_hsrqRequest);
425:
426: return strPath.endsWith(LOGOUT_WEB_PAGE);
427: }
428:
429: /**
430: * Get URL that allows user to display the first page of the list with the
431: * data. The navigator will correctly identify if it is list of blogs or blog
432: * entries and create the proper page URL.
433: *
434: * @return String - url to display the first page of list of data
435: */
436: public String getFirstPageURL() {
437: return getPageOffsetURL(1, true);
438: }
439:
440: /**
441: * Get URL that allows user to display the last page of the list with the
442: * data. The navigator will correctly identify if it is list of blogs or blog
443: * entries and create the proper page URL.
444: *
445: * @return String - url to display the last page of list of data
446: */
447: public String getLastPageURL() {
448: String strUrl = "";
449: ListOptions options;
450:
451: options = (ListOptions) m_hsrqRequest
452: .getAttribute(ListBrowserServlet.PARAMETER_LIST_OPTIONS_NAME);
453: if (options != null) {
454: strUrl = getPageOffsetURL(options.getAbsolutePageCount(),
455: true);
456: } else {
457: s_logger
458: .finest("Unable to construct last page URL since no list"
459: + " options are available.");
460: }
461:
462: return strUrl;
463: }
464:
465: /**
466: * Get URL that allows user to display the previous page of the list with the
467: * data. The navigator will correctly identify if it is list of blogs or blog
468: * entries and create the proper page URL.
469: *
470: * @return String - url to display previous page of list of data
471: */
472: public String getPreviousPageURL() {
473: return getPageOffsetURL(-1, false);
474: }
475:
476: /**
477: * Get URL that allows user to display the next page of the list with the
478: * data. The navigator will correctly identify if it is list of blogs or blog
479: * entries and create the proper page URL.
480: *
481: * @return String - url to display next page of list of data
482: */
483: public String getNextPageURL() {
484: return getPageOffsetURL(1, false);
485: }
486:
487: // Helper methods ///////////////////////////////////////////////////////////
488:
489: /**
490: * Get URL to the root directory where all entries for given blog exist.
491: *
492: * @param strId - ID of the blog to get root URL for
493: * @return String - URL ends with WebCommonConstants.URL_SEPARATOR_CHAR
494: */
495: protected StringBuffer getBlogRootURL(String strId) {
496: StringBuffer sbURL;
497:
498: sbURL = new StringBuffer(m_strBlogDirectoryURL);
499: sbURL.append(strId);
500: sbURL.append(WebCommonConstants.URL_SEPARATOR_CHAR);
501:
502: return sbURL;
503: }
504:
505: /**
506: * Get URL to the page which displays specified blog entry.
507: *
508: * @param strFolder - folder where this entry belongs to
509: * @param iEntryId - id of entry to get page URL for
510: * @return String - URL to the page displaying specified entry
511: */
512: protected String getBlogEntryURL(String strFolder, int iEntryId) {
513: StringBuffer sbURL;
514:
515: sbURL = getBlogRootURL(strFolder);
516: sbURL.append(iEntryId);
517: sbURL.append(WebCommonConstants.WEB_PAGE_EXTENSION);
518:
519: return sbURL.toString();
520: }
521:
522: /**
523: * Get URL that allows user to display same page of the list with the
524: * data. The navigator will correctly identify if it is list of blogs or blog
525: * entries and create the proper page URL.
526: *
527: * @param iOffset - offset of the page to display
528: * @param bAbsolute - if true then the offset is taken as an absolute
529: * otherwise it is relative to current page, +1 will be
530: * the next page, -1 will be the first page
531: * @return String - url to display specified page of list of data
532: */
533: protected String getPageOffsetURL(int iOffset, boolean bAbsolute) {
534: StringBuffer sbBuffer = new StringBuffer();
535: // TODO: Performance: These two methods can cache their results since
536: // they are called repeatedly for the same request
537: boolean bIsBlog = isBlogIndexPage();
538:
539: if (bIsBlog) {
540: // This is list of blogs
541: sbBuffer.append(m_strBlogDirectoryURL);
542: } else {
543: // This is list of entries
544: String strBlogIdentification = (String) getBlogIdentification(m_hsrqRequest);
545:
546: sbBuffer.append(getBlogRootURL(strBlogIdentification));
547: }
548: sbBuffer.append(PAGED_ACCESS_WEB_PAGE);
549: if (bAbsolute) {
550: sbBuffer.append(iOffset);
551: } else {
552: int iPageNumber = isIndexPage();
553: sbBuffer.append(iPageNumber + iOffset);
554: }
555: sbBuffer.append(WebCommonConstants.WEB_PAGE_EXTENSION);
556:
557: return sbBuffer.toString();
558: }
559: }
|