com.alkacon.opencms.formgenerator.CmsCaptchaField.java Source code

Java tutorial

Introduction

Here is the source code for com.alkacon.opencms.formgenerator.CmsCaptchaField.java

Source

/*
 * File   : $Source: /alkacon/cvs/alkacon/com.alkacon.opencms.formgenerator/src/com/alkacon/opencms/formgenerator/CmsCaptchaField.java,v $
 * Date   : $Date: 2011/03/09 15:14:35 $
 * Version: $Revision: 1.12 $
 *
 * This file is part of the Alkacon OpenCms Add-On Module Package
 *
 * Copyright (c) 2010 Alkacon Software GmbH (http://www.alkacon.com)
 *
 * The Alkacon OpenCms Add-On Module Package is free software: 
 * you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * The Alkacon OpenCms Add-On Module Package is distributed 
 * in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with the Alkacon OpenCms Add-On Module Package.  
 * If not, see http://www.gnu.org/licenses/.
 *
 * For further information about Alkacon Software GmbH, please see the
 * company website: http://www.alkacon.com.
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org.
 */

package com.alkacon.opencms.formgenerator;

import org.opencms.flex.CmsFlexController;
import org.opencms.i18n.CmsMessages;
import org.opencms.jsp.CmsJspActionElement;
import org.opencms.main.CmsLog;
import org.opencms.util.CmsStringUtil;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;

import com.octo.captcha.CaptchaException;
import com.octo.captcha.service.CaptchaService;
import com.octo.captcha.service.CaptchaServiceException;
import com.octo.captcha.service.image.ImageCaptchaService;
import com.octo.captcha.service.text.TextCaptchaService;

/**
 * Creates captcha images and validates the pharses submitted by a request parameter.
 * <p>
 * 
 * @author Thomas Weckert
 * 
 * @author Achim Westermann
 * 
 * @version $Revision: 1.12 $
 * 
 * @since 7.0.4 
 */
public class CmsCaptchaField extends A_CmsField {

    /** Request parameter name of the captcha phrase. */
    public static final String C_PARAM_CAPTCHA_PHRASE = "captchaphrase";

    /** Session parameter name to store the webform captcha settings. */
    protected static final String SESSION_PARAM_CAPTCHASETTINGS = "__oamp_webform_captchasettings";

    /** The log object for this class. */
    private static final Log LOG = CmsLog.getLog(CmsCaptchaField.class);

    /** HTML field type: captcha image. */
    private static final String TYPE = "captcha";

    /** The settings to render captcha images. */
    private CmsCaptchaSettings m_captchaSettings;

    /**
     * Creates a new captcha field.
     * <p>
     * 
     * @param captchaSettings the settings to render captcha images
     * @param fieldLabel the localized label of this field
     * @param fieldValue the submitted value of this field
     */
    public CmsCaptchaField(CmsCaptchaSettings captchaSettings, String fieldLabel, String fieldValue) {

        super();

        m_captchaSettings = captchaSettings;

        setName(C_PARAM_CAPTCHA_PHRASE);
        setValue(fieldValue);
        setLabel(fieldLabel);
        setMandatory(true);
    }

    /**
     * Returns the type of the input field, e.g. "text" or "select".
     * <p>
     * 
     * @return the type of the input field
     */
    public static String getStaticType() {

        return TYPE;
    }

    /**
     * @see com.alkacon.opencms.formgenerator.I_CmsField#buildHtml(CmsFormHandler, CmsMessages, String, boolean, String)
     */
    @Override
    public String buildHtml(CmsFormHandler formHandler, CmsMessages messages, String errorKey,
            boolean showMandatory, String infoKey) {

        StringBuffer captchaHtml = new StringBuffer(256);
        String errorMessage = createStandardErrorMessage(errorKey, messages);

        CmsCaptchaSettings captchaSettings = getCaptchaSettings();

        if (m_captchaSettings.isMathField()) {
            // this is a math captcha, print the challenge directly
            String sessionId = formHandler.getRequest().getSession(true).getId();
            TextCaptchaService service = (TextCaptchaService) CmsCaptchaServiceCache.getSharedInstance()
                    .getCaptchaService(m_captchaSettings, formHandler.getCmsObject());
            captchaHtml.append("<div style=\"margin: 0 0 2px 0;\">");
            captchaHtml.append(service.getTextChallengeForID(sessionId,
                    formHandler.getCmsObject().getRequestContext().getLocale()));
            captchaHtml.append("</div>\n");
        } else {
            // image captcha, insert image
            captchaHtml.append("<img id=\"form_captcha_id\" src=\"")
                    .append(formHandler.link("/system/modules/com.alkacon.opencms.formgenerator/pages/captcha.jsp?"
                            + captchaSettings.toRequestParams(formHandler.getCmsObject()) + "#"
                            + System.currentTimeMillis()))
                    .append("\" width=\"").append(captchaSettings.getImageWidth()).append("\" height=\"")
                    .append(captchaSettings.getImageHeight()).append("\" alt=\"\"/>").append("\n");
            captchaHtml.append("<br/>\n");
        }

        Map<String, Object> stAttributes = new HashMap<String, Object>();
        // set captcha HTML code as additional attribute
        stAttributes.put("captcha", captchaHtml.toString());

        return createHtml(formHandler, messages, stAttributes, getType(), null, errorMessage, showMandatory);
    }

    /**
     * Returns the captcha settings of this field.
     * <p>
     * 
     * @return the captcha settings of this field
     */
    public CmsCaptchaSettings getCaptchaSettings() {

        return m_captchaSettings;
    }

    /**
     * @see com.alkacon.opencms.formgenerator.I_CmsField#getType()
     */
    public String getType() {

        return TYPE;
    }

    /**
     * Validates the captcha phrase entered by the user.
     * <p>
     * 
     * @param jsp the Cms JSP
     * @param captchaPhrase the captcha phrase to be validate
     * @return true, if the captcha phrase entered by the user is correct, false otherwise
     */
    public boolean validateCaptchaPhrase(CmsJspActionElement jsp, String captchaPhrase) {

        boolean result = false;
        CmsCaptchaSettings settings = m_captchaSettings;
        // check if there are changed captcha settings stored in the session (true if first image generation failed)
        CmsCaptchaSettings sessionSettings = (CmsCaptchaSettings) jsp.getRequest().getSession()
                .getAttribute(SESSION_PARAM_CAPTCHASETTINGS);
        if (sessionSettings != null) {
            // use captcha settings from session to validate the response
            settings = sessionSettings;
            jsp.getRequest().getSession().removeAttribute(SESSION_PARAM_CAPTCHASETTINGS);
        }
        String sessionId = jsp.getRequest().getSession().getId();

        if (CmsStringUtil.isNotEmpty(captchaPhrase)) {
            // try to validate the phrase
            try {
                CaptchaService captchaService = CmsCaptchaServiceCache.getSharedInstance()
                        .getCaptchaService(settings, jsp.getCmsObject());
                if (captchaService != null) {
                    result = captchaService.validateResponseForID(sessionId, captchaPhrase).booleanValue();
                }
            } catch (CaptchaServiceException cse) {
                // most often this will be
                // "com.octo.captcha.service.CaptchaServiceException: Invalid ID, could not validate unexisting or already validated captcha"
                // in case someone hits the back button and submits again
            }
        }

        return result;
    }

    /**
     * Writes a Captcha JPEG image to the servlet response output stream.
     * <p>
     * 
     * @param cms an initialized Cms JSP action element
     * @throws IOException if something goes wrong
     */
    public void writeCaptchaImage(CmsJspActionElement cms) throws IOException {

        // remove eventual session attribute containing captcha settings
        cms.getRequest().getSession().removeAttribute(SESSION_PARAM_CAPTCHASETTINGS);
        String sessionId = cms.getRequest().getSession().getId();
        Locale locale = cms.getRequestContext().getLocale();
        BufferedImage captchaImage = null;
        int maxTries = 10;
        do {
            try {
                maxTries--;
                captchaImage = ((ImageCaptchaService) CmsCaptchaServiceCache.getSharedInstance()
                        .getCaptchaService(m_captchaSettings, cms.getCmsObject())).getImageChallengeForID(sessionId,
                                locale);
            } catch (CaptchaException cex) {
                // image size is too small, increase dimensions and try it again
                if (LOG.isInfoEnabled()) {
                    LOG.info(cex);
                    LOG.info(Messages.get().getBundle().key(Messages.LOG_ERR_CAPTCHA_CONFIG_IMAGE_SIZE_2,
                            new Object[] { m_captchaSettings.getPresetPath(), new Integer(maxTries) }));
                }
                m_captchaSettings.setImageHeight((int) (m_captchaSettings.getImageHeight() * 1.1));
                m_captchaSettings.setImageWidth((int) (m_captchaSettings.getImageWidth() * 1.1));
                // IMPORTANT: store changed captcha settings in session, they have to be used when validating the phrase
                cms.getRequest().getSession().setAttribute(SESSION_PARAM_CAPTCHASETTINGS,
                        m_captchaSettings.clone());
            }
        } while ((captchaImage == null) && (maxTries > 0));

        ServletOutputStream out = null;
        try {
            CmsFlexController controller = CmsFlexController.getController(cms.getRequest());
            HttpServletResponse response = controller.getTopResponse();
            response.setHeader("Cache-Control", "no-store");
            response.setHeader("Pragma", "no-cache");
            response.setDateHeader("Expires", 0);
            response.setContentType("image/jpeg");

            ByteArrayOutputStream captchaImageOutput = new ByteArrayOutputStream();
            ImageIO.write(captchaImage, "jpg", captchaImageOutput);
            out = cms.getResponse().getOutputStream();
            out.write(captchaImageOutput.toByteArray());
            out.flush();
        } catch (Exception e) {
            if (LOG.isErrorEnabled()) {
                LOG.error(e.getLocalizedMessage(), e);
            }
            cms.getResponse().sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (Throwable t) {
                // intentionally left blank
            }
        }
    }

}