001// Copyright 2011-2013 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007// http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.kaptcha.components;
016
017import org.apache.tapestry5.BindingConstants;
018import org.apache.tapestry5.FieldValidator;
019import org.apache.tapestry5.MarkupWriter;
020import org.apache.tapestry5.annotations.Import;
021import org.apache.tapestry5.annotations.Parameter;
022import org.apache.tapestry5.annotations.SupportsInformalParameters;
023import org.apache.tapestry5.commons.Messages;
024import org.apache.tapestry5.corelib.base.AbstractField;
025import org.apache.tapestry5.internal.TapestryInternalUtils;
026import org.apache.tapestry5.ioc.annotations.Inject;
027import org.apache.tapestry5.kaptcha.KaptchaSymbolConstants;
028import org.apache.tapestry5.services.FieldValidatorSource;
029
030/**
031 * Field paired with a {@link KaptchaImage} to ensure that the user has provided
032 * the correct value. Renders a class attribute of "form-control", which can be extended
033 * via the class informal attribute.
034 *
035 * @since 5.3
036 * @tapestrydoc
037 */
038@SupportsInformalParameters
039@Import(stylesheet = "kaptcha.css")
040public class KaptchaField extends AbstractField
041{
042
043    /**
044     * The image output for this field. The image will display a distorted text
045     * string. The user must decode the distorted text and enter the same value.
046     */
047    @Parameter(required = true, defaultPrefix = BindingConstants.COMPONENT)
048    private KaptchaImage image;
049
050    /**
051     * Controls whether the field is rendered like a password field (false)
052     * or like a normal text field (true, the factory default).
053     *
054     * @see KaptchaSymbolConstants#KAPTCHA_DEFAULT_VISIBLE
055     * @since 5.3
056     */
057    @Parameter("symbol:" + KaptchaSymbolConstants.KAPTCHA_DEFAULT_VISIBLE)
058    private boolean visible;
059
060    @Inject
061    private Messages messages;
062
063    @Inject
064    private FieldValidatorSource fieldValidatorSource;
065
066    /**
067     * Always required.
068     */
069    @Override
070    public boolean isRequired()
071    {
072        return true;
073    }
074
075    @Override
076    protected void processSubmission(String controlName)
077    {
078        String userValue = request.getParameter(controlName);
079
080        validationTracker.recordInput(this, userValue);
081
082        if (TapestryInternalUtils.isEqual(image.getCaptchaText(), userValue))
083            return;
084
085        validationTracker.recordError(this, messages.get("tapestry-incorrect-captcha"));
086    }
087
088    @SuppressWarnings("rawtypes")
089    boolean beginRender(MarkupWriter writer)
090    {
091        writer.element("input",
092
093                "type", visible ? "text" : "password",
094
095                "id", getClientId(),
096
097                "class", "form-control",
098
099                "name", getControlName(),
100
101                "value", visible ? validationTracker.getInput(this) : "");
102
103        resources.renderInformalParameters(writer);
104
105        FieldValidator fieldValidator = fieldValidatorSource.createValidator(this, "required", null);
106
107        fieldValidator.render(writer);
108
109        writer.end();
110
111        return false;
112    }
113}