fr.paris.lutece.plugins.extend.modules.comment.web.CommentApp.java Source code

Java tutorial

Introduction

Here is the source code for fr.paris.lutece.plugins.extend.modules.comment.web.CommentApp.java

Source

/*
 * Copyright (c) 2002-2014, Mairie de Paris
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice
 *     and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright notice
 *     and the following disclaimer in the documentation and/or other materials
 *     provided with the distribution.
 *
 *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * License 1.0
 */
package fr.paris.lutece.plugins.extend.modules.comment.web;

import fr.paris.lutece.plugins.extend.modules.comment.business.Comment;
import fr.paris.lutece.plugins.extend.modules.comment.business.config.CommentExtenderConfig;
import fr.paris.lutece.plugins.extend.modules.comment.service.CommentPlugin;
import fr.paris.lutece.plugins.extend.modules.comment.service.CommentService;
import fr.paris.lutece.plugins.extend.modules.comment.service.ICommentService;
import fr.paris.lutece.plugins.extend.modules.comment.service.extender.CommentResourceExtender;
import fr.paris.lutece.plugins.extend.modules.comment.util.constants.CommentConstants;
import fr.paris.lutece.plugins.extend.service.ExtendPlugin;
import fr.paris.lutece.plugins.extend.service.extender.IResourceExtenderService;
import fr.paris.lutece.plugins.extend.service.extender.ResourceExtenderService;
import fr.paris.lutece.plugins.extend.service.extender.config.IResourceExtenderConfigService;
import fr.paris.lutece.plugins.extend.service.extender.history.IResourceExtenderHistoryService;
import fr.paris.lutece.plugins.extend.service.extender.history.ResourceExtenderHistoryService;
import fr.paris.lutece.portal.business.mailinglist.Recipient;
import fr.paris.lutece.portal.service.captcha.CaptchaSecurityService;
import fr.paris.lutece.portal.service.content.XPageAppService;
import fr.paris.lutece.portal.service.i18n.I18nService;
import fr.paris.lutece.portal.service.mail.MailService;
import fr.paris.lutece.portal.service.mailinglist.AdminMailingListService;
import fr.paris.lutece.portal.service.message.SiteMessage;
import fr.paris.lutece.portal.service.message.SiteMessageException;
import fr.paris.lutece.portal.service.message.SiteMessageService;
import fr.paris.lutece.portal.service.plugin.Plugin;
import fr.paris.lutece.portal.service.plugin.PluginService;
import fr.paris.lutece.portal.service.security.LuteceUser;
import fr.paris.lutece.portal.service.security.SecurityService;
import fr.paris.lutece.portal.service.security.UserNotSignedException;
import fr.paris.lutece.portal.service.spring.SpringContextService;
import fr.paris.lutece.portal.service.template.AppTemplateService;
import fr.paris.lutece.portal.service.util.AppLogService;
import fr.paris.lutece.portal.service.util.AppPathService;
import fr.paris.lutece.portal.service.util.AppPropertiesService;
import fr.paris.lutece.portal.web.constants.Messages;
import fr.paris.lutece.portal.web.util.LocalizedDelegatePaginator;
import fr.paris.lutece.portal.web.xpages.XPage;
import fr.paris.lutece.portal.web.xpages.XPageApplication;
import fr.paris.lutece.util.beanvalidation.BeanValidationUtil;
import fr.paris.lutece.util.html.HtmlTemplate;
import fr.paris.lutece.util.html.IPaginator;
import fr.paris.lutece.util.html.Paginator;
import fr.paris.lutece.util.http.SecurityUtil;
import fr.paris.lutece.util.url.UrlItem;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.ConstraintViolation;

/**
 * 
 * CommentApp
 * 
 */
public class CommentApp implements XPageApplication {
    // MESSAGES
    private static final String MESSAGE_STOP_GENERIC_MESSAGE = "module.extend.comment.message.stop.genericMessage";
    private static final String MESSAGE_ERROR_BAD_JCAPTCHA = "module.extend.comment.message.error.badJcaptcha";

    // PROPERTIES
    private static final String PROPERTY_USE_CAPTCHA = "module.extend.comment.useCaptcha";

    // MARKS
    private static final String MARK_CAPTCHA = "captcha";
    private static final String MARK_IS_ACTIVE_CAPTCHA = "is_active_captcha";

    // TEMPLATES
    private static final String TEMPLATE_XPAGE_VIEW_COMMENTS = "skin/plugins/extend/modules/comment/view_comments.html";
    private static final String TEMPLATE_XPAGE_ADD_COMMENT = "skin/plugins/extend/modules/comment/add_comment.html";
    private static final String TEMPLATE_XPAGE_MESSAGE_COMMENT_CREATED = "skin/plugins/extend/modules/comment/message_comment_created.html";
    private static final String TEMPLATE_COMMENT_NOTIFY_MESSAGE = "skin/plugins/extend/modules/comment/comment_notify_message.html";

    private static final String JSP_URL_DEFAULT_POST_BACK = "jsp/site/Portal.jsp?page=extend-comment";

    // CONSTANTS
    private static final String JCAPTCHA_PLUGIN = "jcaptcha";
    private static final String HTML_BR = "<br />";
    private static final String FROM_SESSION = "from_session";
    private static final String CONSTANT_AND = "&";
    private static final String CONSTANT_AND_HTML = "%26";

    // VARIABLES
    private static ICommentService _commentService;
    private static IResourceExtenderConfigService _configService;
    private static IResourceExtenderService _resourceExtenderService;
    private static IResourceExtenderHistoryService _resourceHistoryService;

    private static int _nDefaultItemsPerPage;

    private final boolean _bIsCaptchaEnabled = PluginService.isPluginEnable(JCAPTCHA_PLUGIN) && Boolean
            .parseBoolean(AppPropertiesService.getProperty(PROPERTY_USE_CAPTCHA, Boolean.TRUE.toString()));

    /**
     * {@inheritDoc}
     */
    @Override
    public XPage getPage(HttpServletRequest request, int nMode, Plugin plugin)
            throws UserNotSignedException, SiteMessageException {
        XPage page = null;

        // Check if the extender is indeed in the parameters
        String strIdExtendableResource = request.getParameter(CommentConstants.PARAMETER_ID_EXTENDABLE_RESOURCE);
        String strExtendableResourceType = request
                .getParameter(CommentConstants.PARAMETER_EXTENDABLE_RESOURCE_TYPE);

        if (StringUtils.isBlank(strIdExtendableResource) || StringUtils.isBlank(strExtendableResourceType)) {
            SiteMessageService.setMessage(request, Messages.MANDATORY_FIELDS, SiteMessage.TYPE_STOP);
        }

        String strAction = request.getParameter(CommentConstants.PARAMETER_ACTION);

        if (StringUtils.isNotBlank(strAction)) {
            if (CommentConstants.ACTION_ADD_COMMENT.equals(strAction)) {
                page = getAddCommentPage(request, strIdExtendableResource, strExtendableResourceType);
            } else if (CommentConstants.ACTION_DO_ADD_COMMENT.equals(strAction)) {
                page = doAddComment(request, strIdExtendableResource, strExtendableResourceType);
            }
        }

        if (page == null) {
            page = getViewCommentPage(request, strIdExtendableResource, strExtendableResourceType);
        }

        return page;
    }

    /**
     * Gets the view comment page.
     * 
     * @param request the request
     * @param strIdExtendableResource the str id extendable resource
     * @param strExtendableResourceType the str extendable resource type
     * @param strPostBackUrl The URL to use for post backs.
     * @return the view comment page
     */
    public static String getViewCommentPageContent(HttpServletRequest request, String strIdExtendableResource,
            String strExtendableResourceType, String strPostBackUrl) {
        request.getSession().setAttribute(ExtendPlugin.PLUGIN_NAME + CommentConstants.SESSION_COMMENT_POST_BACK_URL,
                strPostBackUrl);

        Integer nItemsPerPage = getDefaultItemsPerPage();
        String strCurrentPageIndex = CommentConstants.CONSTANT_FIRST_PAGE_NUMBER;
        Boolean bIsAscSort = false;
        Object object = request.getSession().getAttribute(CommentConstants.SESSION_COMMENT_ITEMS_PER_PAGE);
        if (object != null) {
            nItemsPerPage = (Integer) object;
        }
        object = request.getSession().getAttribute(CommentConstants.SESSION_COMMENT_CURRENT_PAGE_INDEX);
        if (object != null) {
            strCurrentPageIndex = (String) object;
        }
        object = request.getSession().getAttribute(CommentConstants.SESSION_COMMENT_IS_ASC_SORT);
        if (object != null) {
            bIsAscSort = (Boolean) object;
        }

        String strSort = request.getParameter(CommentConstants.MARK_ASC_SORT);
        if (!StringUtils.isEmpty(strSort)) {
            bIsAscSort = Boolean.parseBoolean(strSort);
        }

        String strFromUrl = request.getParameter(CommentConstants.PARAMETER_FROM_URL);
        if (FROM_SESSION.equals(strFromUrl)) {
            strFromUrl = (String) request.getSession()
                    .getAttribute(ExtendPlugin.PLUGIN_NAME + CommentConstants.PARAMETER_FROM_URL);
        }
        if (StringUtils.isEmpty(strFromUrl)) {
            strFromUrl = request.getHeader(CommentConstants.PARAMETER_REFERER);
        }
        if (strFromUrl != null) {
            strFromUrl = strFromUrl.replace(CONSTANT_AND, CONSTANT_AND_HTML);
        }
        request.getSession().setAttribute(ExtendPlugin.PLUGIN_NAME + CommentConstants.PARAMETER_FROM_URL,
                strFromUrl);

        strCurrentPageIndex = Paginator.getPageIndex(request, Paginator.PARAMETER_PAGE_INDEX, strCurrentPageIndex);
        int nOldITemsPerPage = nItemsPerPage;
        nItemsPerPage = Paginator.getItemsPerPage(request, Paginator.PARAMETER_ITEMS_PER_PAGE, nItemsPerPage,
                getDefaultItemsPerPage());
        if (nItemsPerPage <= 0) {
            nItemsPerPage = getDefaultItemsPerPage();
        }
        // If we changed the number of items per page, we go back to the first page
        if (nItemsPerPage != nOldITemsPerPage) {
            strCurrentPageIndex = CommentConstants.CONSTANT_FIRST_PAGE_NUMBER;
        }
        UrlItem urlSort = new UrlItem(strPostBackUrl);
        urlSort.addParameter(CommentConstants.MARK_ID_EXTENDABLE_RESOURCE, strIdExtendableResource);
        urlSort.addParameter(CommentConstants.MARK_EXTENDABLE_RESOURCE_TYPE, strExtendableResourceType);
        urlSort.addParameter(CommentConstants.MARK_ASC_SORT, strSort);
        if (StringUtils.isNotEmpty(strFromUrl)) {
            urlSort.addParameter(CommentConstants.PARAMETER_FROM_URL, FROM_SESSION);
        }
        boolean bGetSubComments = false;
        boolean bUseBBCodeEditor = false;
        boolean bAllowSubComments = false;
        String strAdminBadge = StringUtils.EMPTY;
        CommentExtenderConfig config = getConfigService().find(CommentResourceExtender.EXTENDER_TYPE_COMMENT,
                strIdExtendableResource, strExtendableResourceType);
        if (config != null) {
            bGetSubComments = config.getAuthorizeSubComments();
            bUseBBCodeEditor = config.getUseBBCodeEditor();
            bAllowSubComments = config.getAuthorizeSubComments();
            strAdminBadge = config.getAdminBadge();
        }
        int nItemsOffset = nItemsPerPage * (Integer.parseInt(strCurrentPageIndex) - 1);

        List<Comment> listItems = getCommentService().findByResource(strIdExtendableResource,
                strExtendableResourceType, true, null, bIsAscSort, nItemsOffset, nItemsPerPage, bGetSubComments);

        int nItemsCount = getCommentService().getCommentNb(strIdExtendableResource, strExtendableResourceType, true,
                true);

        IPaginator<Comment> paginator = new LocalizedDelegatePaginator<Comment>(listItems, nItemsPerPage,
                urlSort.getUrl(), Paginator.PARAMETER_PAGE_INDEX, strCurrentPageIndex, nItemsCount,
                request.getLocale());

        Map<String, Object> model = new HashMap<String, Object>();
        model.put(CommentConstants.MARK_ID_EXTENDABLE_RESOURCE, strIdExtendableResource);
        model.put(CommentConstants.MARK_EXTENDABLE_RESOURCE_TYPE, strExtendableResourceType);
        model.put(CommentConstants.MARK_PAGINATOR, paginator);
        model.put(CommentConstants.MARK_ASC_SORT, strSort);
        model.put(CommentConstants.PARAMETER_FROM_URL, strFromUrl);
        model.put(CommentConstants.PARAMETER_ID_COMMENT,
                request.getParameter(CommentConstants.PARAMETER_ID_COMMENT));
        model.put(CommentConstants.MARK_USE_BBCODE, bUseBBCodeEditor);
        model.put(CommentConstants.MARK_ALLOW_SUB_COMMENTS, bAllowSubComments);
        model.put(CommentConstants.MARK_ADMIN_BADGE, strAdminBadge);
        model.put(CommentConstants.PARAMETER_POST_BACK_URL, strPostBackUrl);

        HtmlTemplate template = AppTemplateService.getTemplate(TEMPLATE_XPAGE_VIEW_COMMENTS, request.getLocale(),
                model);

        HttpSession session = request.getSession();
        session.setAttribute(CommentConstants.SESSION_COMMENT_ITEMS_PER_PAGE, nItemsPerPage);
        session.setAttribute(CommentConstants.SESSION_COMMENT_CURRENT_PAGE_INDEX, strCurrentPageIndex);
        session.setAttribute(CommentConstants.SESSION_COMMENT_IS_ASC_SORT, bIsAscSort);

        return template.getHtml();
    }

    /**
     * Gets the view comment page.
     * 
     * @param request the request
     * @param strIdExtendableResource the str id extendable resource
     * @param strExtendableResourceType the str extendable resource type
     * @return the view comment page
     */
    public XPage getViewCommentPage(HttpServletRequest request, String strIdExtendableResource,
            String strExtendableResourceType) {
        XPage page = new XPage();
        page.setTitle(I18nService.getLocalizedString(CommentConstants.PROPERTY_XPAGE_VIEW_COMMENTS_PAGE_TITLE,
                request.getLocale()));
        page.setPathLabel(I18nService.getLocalizedString(CommentConstants.PROPERTY_XPAGE_VIEW_COMMENTS_PATH_LABEL,
                request.getLocale()));

        page.setContent(getViewCommentPageContent(request, strIdExtendableResource, strExtendableResourceType,
                JSP_URL_DEFAULT_POST_BACK));
        return page;
    }

    /**
     * Gets the adds the comment page.
     * 
     * @param request the request
     * @param strIdExtendableResource the str id extendable resource
     * @param strExtendableResourceType the str extendable resource type
     * @return the adds the comment page
     */
    private XPage getAddCommentPage(HttpServletRequest request, String strIdExtendableResource,
            String strExtendableResourceType) {
        XPage page = new XPage();

        page.setTitle(I18nService.getLocalizedString(CommentConstants.PROPERTY_XPAGE_ADD_COMMENT_PAGE_TITLE,
                request.getLocale()));
        page.setPathLabel(I18nService.getLocalizedString(CommentConstants.PROPERTY_XPAGE_ADD_COMMENT_PAGE_LABEL,
                request.getLocale()));

        CommentExtenderConfig config = getConfigService().find(CommentResourceExtender.EXTENDER_TYPE_COMMENT,
                strIdExtendableResource, strExtendableResourceType);

        String strFromUrl = request.getParameter(CommentConstants.PARAMETER_FROM_URL);
        if (FROM_SESSION.equals(strFromUrl)) {
            strFromUrl = (String) request.getSession()
                    .getAttribute(ExtendPlugin.PLUGIN_NAME + CommentConstants.PARAMETER_FROM_URL);
        }
        if (StringUtils.isEmpty(strFromUrl)) {
            strFromUrl = request.getHeader(CommentConstants.PARAMETER_REFERER);
        }
        if (strFromUrl != null) {
            strFromUrl = strFromUrl.replace(CONSTANT_AND, CONSTANT_AND_HTML);
        }
        request.getSession().setAttribute(ExtendPlugin.PLUGIN_NAME + CommentConstants.PARAMETER_FROM_URL,
                strFromUrl);

        Map<String, Object> model = new HashMap<String, Object>();
        model.put(CommentConstants.MARK_COMMENT_CONFIG, config);
        model.put(CommentConstants.MARK_ID_EXTENDABLE_RESOURCE, strIdExtendableResource);
        model.put(CommentConstants.MARK_EXTENDABLE_RESOURCE_TYPE, strExtendableResourceType);
        model.put(CommentConstants.PARAMETER_FROM_URL, strFromUrl);
        model.put(CommentConstants.MARK_RETURN_TO_COMMENT_LIST,
                Boolean.parseBoolean(request.getParameter(CommentConstants.MARK_RETURN_TO_COMMENT_LIST)));
        model.put(CommentConstants.PARAMETER_ID_COMMENT,
                request.getParameter(CommentConstants.PARAMETER_ID_COMMENT));
        model.put(CommentConstants.MARK_WEBAPP_URL, AppPathService.getBaseUrl(request));
        model.put(CommentConstants.MARK_LOCALE, Locale.getDefault());

        // Add Captcha
        model.put(MARK_IS_ACTIVE_CAPTCHA, _bIsCaptchaEnabled);

        if (_bIsCaptchaEnabled) {
            CaptchaSecurityService captchaService = new CaptchaSecurityService();
            model.put(MARK_CAPTCHA, captchaService.getHtmlCode());
        }

        if (SecurityService.isAuthenticationEnable()) {
            LuteceUser user = SecurityService.getInstance().getRegisteredUser(request);

            if (user != null) {
                model.put(CommentConstants.MARK_MYLUTECE_USER, user);
            }
        }

        HtmlTemplate template = AppTemplateService.getTemplate(TEMPLATE_XPAGE_ADD_COMMENT, request.getLocale(),
                model);

        page.setContent(template.getHtml());

        return page;
    }

    /**
     * Do add comment.
     * 
     * @param request the request
     * @param strIdExtendableResource the str id extendable resource
     * @param strExtendableResourceType the str extendable resource type
     * @return The page to display, or null to display the default page
     * @throws SiteMessageException the site message exception
     */
    private XPage doAddComment(HttpServletRequest request, String strIdExtendableResource,
            String strExtendableResourceType) throws SiteMessageException {
        Comment comment = new Comment();

        try {
            BeanUtils.populate(comment, request.getParameterMap());
        } catch (IllegalAccessException e) {
            AppLogService.error("Unable to fetch data from request", e);
        } catch (InvocationTargetException e) {
            AppLogService.error("Unable to fetch data from request", e);
        }

        // Check mandatory fields
        Set<ConstraintViolation<Comment>> constraintViolations = BeanValidationUtil.validate(comment);

        if (constraintViolations.size() > 0) {
            Object[] params = { buildStopMessage(constraintViolations) };

            SiteMessageService.setMessage(request, MESSAGE_STOP_GENERIC_MESSAGE, params, SiteMessage.TYPE_STOP);
        }

        if (StringUtils.isBlank(comment.getName()) || StringUtils.isBlank(comment.getComment())
                || StringUtils.isBlank(comment.getEmail())) {
            SiteMessageService.setMessage(request, Messages.MANDATORY_FIELDS, SiteMessage.TYPE_STOP);
        }

        // Test the captcha
        if (_bIsCaptchaEnabled) {
            CaptchaSecurityService captchaService = new CaptchaSecurityService();

            if (!captchaService.validate(request)) {
                SiteMessageService.setMessage(request, MESSAGE_ERROR_BAD_JCAPTCHA, SiteMessage.TYPE_STOP);
            }
        }

        CommentExtenderConfig config = getConfigService().find(CommentResourceExtender.EXTENDER_TYPE_COMMENT,
                strIdExtendableResource, strExtendableResourceType);

        if (config != null) {
            comment.setIpAddress(SecurityUtil.getRealIp(request));
            comment.setIdExtendableResource(strIdExtendableResource);
            comment.setExtendableResourceType(strExtendableResourceType);
            comment.setPublished(!config.isModerated());
            if (!config.getAuthorizeSubComments()) {
                comment.setIdParentComment(0);
            }
            boolean bIsCreated = false;

            try {
                getCommentService().create(comment);
                bIsCreated = true;
            } catch (Exception ex) {
                // Something wrong happened... a database check might be needed
                AppLogService.error(ex.getMessage() + " when creating a comment ", ex);
                // Revert
                getCommentService().remove(comment.getIdComment());

                SiteMessageService.setMessage(request, CommentConstants.MESSAGE_ERROR_GENERIC_MESSAGE,
                        SiteMessage.TYPE_ERROR);
            }

            if (bIsCreated) {
                // Add to the resource extender history
                getResourceExtenderHistoryService().create(CommentResourceExtender.EXTENDER_TYPE_COMMENT,
                        strIdExtendableResource, strExtendableResourceType, request);

                // Notify the mailing list
                sendCommentNotification(request, comment, config);

                XPage page = new XPage();
                page.setTitle(I18nService.getLocalizedString(CommentConstants.PROPERTY_XPAGE_ADD_COMMENT_PAGE_TITLE,
                        request.getLocale()));
                page.setPathLabel(I18nService.getLocalizedString(
                        CommentConstants.PROPERTY_XPAGE_ADD_COMMENT_PAGE_LABEL, request.getLocale()));

                String strPostBackUrl = (String) request.getSession()
                        .getAttribute(ExtendPlugin.PLUGIN_NAME + CommentConstants.SESSION_COMMENT_POST_BACK_URL);
                if (strPostBackUrl == null) {
                    strPostBackUrl = JSP_URL_DEFAULT_POST_BACK;
                }
                String strFromUrl = request.getParameter(CommentConstants.PARAMETER_FROM_URL);
                if (FROM_SESSION.equals(strFromUrl)) {
                    strFromUrl = (String) request.getSession()
                            .getAttribute(ExtendPlugin.PLUGIN_NAME + CommentConstants.PARAMETER_FROM_URL);
                }
                if (strFromUrl != null) {
                    strFromUrl = strFromUrl.replaceAll(CONSTANT_AND_HTML, CONSTANT_AND);
                }
                Map<String, Object> model = new HashMap<String, Object>();
                model.put(CommentConstants.MARK_MESSAGE_COMMENT_CREATED, config.getMessageCommentCreated());
                model.put(CommentConstants.MARK_ID_EXTENDABLE_RESOURCE, strIdExtendableResource);
                model.put(CommentConstants.MARK_EXTENDABLE_RESOURCE_TYPE, strExtendableResourceType);
                model.put(CommentConstants.PARAMETER_ID_COMMENT,

                        comment.getIdParentComment() == 0 ? comment.getIdComment() : comment.getIdParentComment());
                model.put(CommentConstants.PARAMETER_POST_BACK_URL, strPostBackUrl);
                model.put(CommentConstants.MARK_RETURN_TO_COMMENT_LIST,
                        Boolean.parseBoolean(request.getParameter(CommentConstants.MARK_RETURN_TO_COMMENT_LIST)));
                model.put(CommentConstants.PARAMETER_FROM_URL, strFromUrl);

                HtmlTemplate template = AppTemplateService.getTemplate(TEMPLATE_XPAGE_MESSAGE_COMMENT_CREATED,
                        request.getLocale(), model);

                page.setContent(template.getHtml());

                return page;
            }
            return null;
        }
        SiteMessageService.setMessage(request, CommentConstants.MESSAGE_ERROR_GENERIC_MESSAGE,
                SiteMessage.TYPE_ERROR);
        return null;
    }

    /**
     * Builds the stop message.
     * 
     * @param <A> the generic type
     * @param listErrors the list errors
     * @return the string
     */
    private static <A> String buildStopMessage(Set<ConstraintViolation<A>> listErrors) {
        StringBuilder sbError = new StringBuilder();

        if ((listErrors != null) && !listErrors.isEmpty()) {
            for (ConstraintViolation<A> error : listErrors) {
                sbError.append(error.getMessage());
                sbError.append(HTML_BR);
            }
        }

        return sbError.toString();
    }

    /**
     * Send comment notification.
     * 
     * @param request the request
     * @param comment the document comment
     * @param config the config
     */
    private void sendCommentNotification(HttpServletRequest request, Comment comment,
            CommentExtenderConfig config) {
        int nMailingListId = config.getIdMailingList();
        Collection<Recipient> listRecipients = AdminMailingListService.getRecipients(nMailingListId);

        for (Recipient recipient : listRecipients) {
            Map<String, Object> model = new HashMap<String, Object>();

            String strSenderEmail = comment.getEmail();
            String strSenderName = comment.getName();
            String strResourceName = getResourceExtenderService().getExtendableResourceName(
                    comment.getIdExtendableResource(), comment.getExtendableResourceType());

            Object[] params = { strResourceName };
            String strSubject = I18nService.getLocalizedString(CommentConstants.MESSAGE_NOTIFY_SUBJECT, params,
                    request.getLocale());

            UrlItem url = new UrlItem(AppPathService.getBaseUrl(request) + AppPathService.getPortalUrl());
            url.addParameter(XPageAppService.PARAM_XPAGE_APP, CommentPlugin.PLUGIN_NAME);
            url.addParameter(CommentConstants.PARAMETER_ID_EXTENDABLE_RESOURCE, comment.getIdExtendableResource());
            url.addParameter(CommentConstants.PARAMETER_EXTENDABLE_RESOURCE_TYPE,
                    comment.getExtendableResourceType());

            model.put(CommentConstants.MARK_RESOURCE_EXTENDER_NAME, strResourceName);
            model.put(CommentConstants.MARK_RESOURCE_EXTENDER_URL, url.getUrl());
            model.put(CommentConstants.MARK_COMMENT, comment);

            HtmlTemplate template = AppTemplateService.getTemplate(TEMPLATE_COMMENT_NOTIFY_MESSAGE,
                    request.getLocale(), model);
            String strBody = template.getHtml();

            MailService.sendMailHtml(recipient.getEmail(), strSenderName, strSenderEmail, strSubject, strBody);
        }
    }

    /**
     * Get the default number of items per page
     * @return the default number of items per page
     */
    private static int getDefaultItemsPerPage() {
        if (_nDefaultItemsPerPage == 0) {
            _nDefaultItemsPerPage = AppPropertiesService
                    .getPropertyInt(CommentConstants.PROPERTY_DEFAULT_LIST_COMMENTS_PER_PAGE, 50);
        }
        return _nDefaultItemsPerPage;
    }

    /**
     * Get the comment service
     * @return the comment service
     */
    private static ICommentService getCommentService() {
        if (_commentService == null) {
            _commentService = SpringContextService.getBean(CommentService.BEAN_SERVICE);
        }
        return _commentService;
    }

    /**
     * Get the config service
     * @return the config service
     */
    private static IResourceExtenderConfigService getConfigService() {
        if (_configService == null) {
            _configService = SpringContextService.getBean(CommentConstants.BEAN_CONFIG_SERVICE);
        }
        return _configService;
    }

    /**
     * Get the resource extender service
     * @return the resource extender service
     */
    private static IResourceExtenderService getResourceExtenderService() {
        if (_resourceExtenderService == null) {
            _resourceExtenderService = SpringContextService.getBean(ResourceExtenderService.BEAN_SERVICE);
        }
        return _resourceExtenderService;
    }

    /**
     * Get the resource extender history service
     * @return the resource extender history service
     */
    private static IResourceExtenderHistoryService getResourceExtenderHistoryService() {
        if (_resourceHistoryService == null) {
            _resourceHistoryService = SpringContextService.getBean(ResourceExtenderHistoryService.BEAN_SERVICE);
        }
        return _resourceHistoryService;
    }
}