001    // Copyright 2011, 2012 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    
015    package org.apache.tapestry5.kaptcha.components;
016    
017    import org.apache.tapestry5.*;
018    import org.apache.tapestry5.annotations.Environmental;
019    import org.apache.tapestry5.annotations.Import;
020    import org.apache.tapestry5.annotations.Parameter;
021    import org.apache.tapestry5.annotations.SupportsInformalParameters;
022    import org.apache.tapestry5.corelib.base.AbstractField;
023    import org.apache.tapestry5.internal.TapestryInternalUtils;
024    import org.apache.tapestry5.ioc.Messages;
025    import org.apache.tapestry5.ioc.annotations.Inject;
026    import org.apache.tapestry5.kaptcha.KaptchaSymbolConstants;
027    import org.apache.tapestry5.services.FieldValidatorSource;
028    import org.apache.tapestry5.services.Request;
029    
030    /**
031     * Field paired with a {@link KaptchaImage} to ensure that the user has provided
032     * the correct value.
033     *
034     * @since 5.3
035     * @tapestrydoc
036     */
037    @SupportsInformalParameters
038    @Import(stylesheet = "kaptcha.css")
039    public class KaptchaField extends AbstractField
040    {
041    
042        /**
043         * The image output for this field. The image will display a distorted text
044         * string. The user must decode the distorted text and enter the same value.
045         */
046        @Parameter(required = true, defaultPrefix = BindingConstants.COMPONENT)
047        private KaptchaImage image;
048    
049        /**
050         * Controls whether the field is rendered like a password field (false, the factory default)
051         * or like a normal text field (true).
052         *
053         * @see KaptchaSymbolConstants#KAPTCHA_DEFAULT_VISIBLE
054         * @since 5.3
055         */
056        @Parameter("symbol:" + KaptchaSymbolConstants.KAPTCHA_DEFAULT_VISIBLE)
057        private boolean visible;
058    
059        @Inject
060        private Request request;
061    
062        @Inject
063        private Messages messages;
064    
065        @Inject
066        private ComponentResources resources;
067    
068        @Environmental
069        private ValidationTracker validationTracker;
070    
071        @Inject
072        private FieldValidatorSource fieldValidatorSource;
073    
074        /**
075         * Always required.
076         */
077        @Override
078        public boolean isRequired()
079        {
080            return true;
081        }
082    
083        @Override
084        protected void processSubmission(String controlName)
085        {
086            String userValue = request.getParameter(controlName);
087    
088            validationTracker.recordInput(this, userValue);
089    
090            if (TapestryInternalUtils.isEqual(image.getCaptchaText(), userValue))
091                return;
092    
093            validationTracker.recordError(this, messages.get("tapestry-incorrect-captcha"));
094        }
095    
096        @SuppressWarnings("rawtypes")
097        boolean beginRender(MarkupWriter writer)
098        {
099            writer.element("input",
100    
101                    "type", visible ? "text" : "password",
102    
103                    "id", getClientId(),
104    
105                    "name", getControlName(),
106    
107                    "value", visible ? validationTracker.getInput(this) : "");
108    
109            resources.renderInformalParameters(writer);
110    
111            FieldValidator fieldValidator = fieldValidatorSource.createValidator(this, "required", null);
112    
113            fieldValidator.render(writer);
114    
115            writer.end();
116    
117            return false;
118        }
119    }