    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.ComponentResources;
    018    import org.apache.tapestry5.Link;
    019    import org.apache.tapestry5.MarkupWriter;
    020    import org.apache.tapestry5.annotations.Persist;
    021    import org.apache.tapestry5.annotations.SupportsInformalParameters;
    022    import org.apache.tapestry5.ioc.annotations.Inject;
    023    import org.apache.tapestry5.kaptcha.services.KaptchaProducer;
    024    import org.apache.tapestry5.services.Response;
    025
    026    import javax.imageio.ImageIO;
    027    import java.awt.image.BufferedImage;
    028    import java.io.IOException;
    029    import java.io.OutputStream;
    030
    031    /**
    032     * Part of a Captcha based authentication scheme; a KaptchaImage generates a new
    033     * text image whenever it <em>renders</em> and can provide the previously
    034     * rendered text subsequently (it is stored persistently in the session).
    035     * <p/>
    036     * The component renders an {@code <img>} tag, including width and height attributes. Other attributes
    037     * come from informal parameters.
    038     *
    039     * @tapestrydoc
    040     * @since 5.3
    041     */
    042    @SupportsInformalParameters
    043    public class KaptchaImage
    044    {
    045
    046        @Persist
    047        private String captchaText;
    048
    049        @Inject
    050        private KaptchaProducer producer;
    051
    052        @Inject
    053        private ComponentResources resources;
    054
    055        @Inject
    056        private Response response;
    057
    058        public String getCaptchaText()
    059        {
    060            return captchaText;
    061        }
    062
    063        void setupRender()
    064        {
    065            captchaText = producer.createText();
    066        }
    067
    068        boolean beginRender(MarkupWriter writer)
    069        {
    070            Link link = resources.createEventLink("image");
    071
    072            writer.element("img",
    073
    074                    "src", link.toURI(),
    075
    076                    "width", producer.getWidth(),
    077
    078                    "height", producer.getHeight());
    079
    080            resources.renderInformalParameters(writer);
    081
    082            writer.end();
    083
    084            return false;
    085        }
    086
    087        void onImage() throws IOException
    088        {
    089            BufferedImage image = producer.createImage(captchaText);
    090
    091            response.setDateHeader("Expires", 0);
    092            // Set standard HTTP/1.1 no-cache headers.
    093            response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
    094            // Set IE extended HTTP/1.1 no-cache headers (use addHeader).
    095            response.setHeader("Cache-Control", "post-check=0, pre-check=0");
    096            // Set standard HTTP/1.0 no-cache header.
    097            response.setHeader("Pragma", "no-cache");
    098
    099            OutputStream stream = response.getOutputStream("image/jpeg");
    100
    101            ImageIO.write(image, "jpg", stream);
    102
    103            stream.flush();
    104
    105            stream.close();
    106        }
    107    }