You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2010/04/29 00:57:24 UTC

svn commit: r939128 - in /myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha: ./ CAPTCHARenderer.java util/ util/CAPTCHAImageGenerator.java

Author: lu4242
Date: Wed Apr 28 22:57:24 2010
New Revision: 939128

URL: http://svn.apache.org/viewvc?rev=939128&view=rev
Log:
TOMAHAWK-1501 Use new jsf 2.0 Resource api on CAPTCHA component

Added:
    myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha/
    myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha/CAPTCHARenderer.java
    myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha/util/
    myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha/util/CAPTCHAImageGenerator.java

Added: myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha/CAPTCHARenderer.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha/CAPTCHARenderer.java?rev=939128&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha/CAPTCHARenderer.java (added)
+++ myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha/CAPTCHARenderer.java Wed Apr 28 22:57:24 2010
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.custom.captcha;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.util.Map;
+
+import javax.faces.FacesException;
+import javax.faces.FactoryFinder;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.context.FacesContextFactory;
+import javax.faces.context.ResponseStream;
+import javax.faces.context.ResponseWriter;
+import javax.faces.lifecycle.Lifecycle;
+import javax.faces.lifecycle.LifecycleFactory;
+import javax.faces.render.Renderer;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.myfaces.component.html.util.HtmlComponentUtils;
+import org.apache.myfaces.component.html.util.ParameterResourceHandler;
+import org.apache.myfaces.custom.captcha.util.CAPTCHAConstants;
+import org.apache.myfaces.custom.captcha.util.CAPTCHAImageGenerator;
+import org.apache.myfaces.custom.captcha.util.CAPTCHAResponseStream;
+import org.apache.myfaces.custom.captcha.util.CAPTCHATextGenerator;
+import org.apache.myfaces.custom.captcha.util.ColorGenerator;
+import org.apache.myfaces.renderkit.html.util.AddResource;
+import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
+import org.apache.myfaces.renderkit.html.util.ResourceLoader;
+
+import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
+
+/**
+ *
+ * @JSFRenderer
+ *   renderKitId = "HTML_BASIC"
+ *   family = "org.apache.myfaces.CAPTCHA"
+ *   type = "org.apache.myfaces.CAPTCHA"
+ * @since 1.1.7
+ * @author Hazem Saleh
+ *
+ */
+public class CAPTCHARenderer extends Renderer implements ResourceLoader
+{
+
+    public void encodeBegin(FacesContext context, UIComponent component)
+            throws IOException
+    {
+
+        CAPTCHAComponent captchaComponent = (CAPTCHAComponent) component;
+
+        generateImageTag(context, captchaComponent);
+    }
+
+    public void encodeEnd(FacesContext context, UIComponent component)
+            throws IOException
+    {
+        super.encodeEnd(context, component);
+    }
+
+    /*
+     * This helper method is used for generating the img tag that will
+     * use the (AddResource) to generate the url of the generated image.
+     */
+    private void generateImageTag(FacesContext context,
+            CAPTCHAComponent component) throws IOException
+    {
+
+        AddResource addResource;
+        ResponseWriter writer = context.getResponseWriter();
+        Map params = HtmlComponentUtils.getParameterMap(component);
+        String url;
+        String captchaSessionKeyName = component.getCaptchaSessionKeyName();
+        String width = component.getImageWidth();
+        String height = component.getImageHeight();
+
+        // determine width and height of the generated image.
+        if (width == null)
+        {
+            width = CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH + "";
+        }
+
+        if (height == null)
+        {
+            height = CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT + "";
+        }
+
+        writer.startElement(HTML.IMG_ELEM, component);
+
+        // constructing the parameter map to be passed to the (AddResource).
+        if (captchaSessionKeyName != null)
+        {
+            params.put(CAPTCHAComponent.ATTRIBUTE_CAPTCHA_SESSION_KEY_NAME,
+                    captchaSessionKeyName);
+        }
+
+        // write the url to trigger the (AddResource).
+        addResource = AddResourceFactory.getInstance(context);
+
+        url = context.getExternalContext().encodeResourceURL(
+                addResource.getResourceUri(context,
+                        new ParameterResourceHandler(this.getClass(), params)));
+
+        // adding dummy parameter to prevent caching.
+        writer.writeAttribute(HTML.SRC_ATTR, url + "&dummyParameter="
+                + System.currentTimeMillis(), null);
+
+        // write rest of attributes.
+        writer.writeAttribute(HTML.WIDTH_ATTR, width, null);
+
+        writer.writeAttribute(HTML.HEIGHT_ATTR, height, null);
+
+        writer.endElement(HTML.IMG_ELEM);
+    }
+
+    /*
+     * This method is implemented to be called from the (AddResource).
+     * It wraps the CAPTCHA image generation.
+     */
+    public void serveResource(ServletContext servletContext,
+            HttpServletRequest request, HttpServletResponse response,
+            String resourceUri) throws IOException
+    {
+
+        // get the FacesContext from the ServletContext.
+        FacesContextFactory facesContextFactory = (FacesContextFactory) FactoryFinder
+                .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
+        LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
+                .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
+        Lifecycle lifecycle = lifecycleFactory.getLifecycle(HtmlComponentUtils
+                .getLifecycleId(servletContext));
+        FacesContext facesContext = facesContextFactory.getFacesContext(
+                servletContext, request, response, lifecycle);
+        facesContext.setResponseStream(new CAPTCHAResponseStream(response
+                .getOutputStream()));
+
+        // render the CAPTCHA.
+        try
+        {
+            try
+            {
+                renderCAPTCHA(facesContext);
+            }
+            catch (IOException e)
+            {
+                throw new FacesException("Could not render the CAPTCHA : "
+                        + e.getMessage(), e);
+            }
+            facesContext.getResponseStream().close();
+        }
+        finally
+        {
+            facesContext.release();
+        }
+    }
+
+    /*
+     * This method is used for rendering the CAPTCHA component.
+     */
+    protected void renderCAPTCHA(FacesContext facesContext) throws IOException
+    {
+
+        // getting CAPTCHA attributes.
+        HttpServletResponse response = (HttpServletResponse) facesContext
+                .getExternalContext().getResponse();
+        ResponseStream out = facesContext.getResponseStream();
+        Map requestMap = facesContext.getExternalContext()
+                .getRequestParameterMap();
+        String captchaSessionKeyName = requestMap.get(
+                CAPTCHAComponent.ATTRIBUTE_CAPTCHA_SESSION_KEY_NAME).toString();
+
+        // construct the CAPTCHA image generator object.
+        CAPTCHAImageGenerator captchaImageGenerator = new CAPTCHAImageGenerator();
+
+        try
+        {
+            String captchaText;
+            Color endingColor = ColorGenerator.generateRandomColor(null);
+            Color startingColor = ColorGenerator
+                    .generateRandomColor(endingColor);
+
+            // Generate random CAPTCHA text.
+            captchaText = CAPTCHATextGenerator.generateRandomText();
+
+            // Generate the image, the BG color is randomized from starting to ending colors.
+            captchaImageGenerator.generateImage(response, captchaText,
+                    startingColor, endingColor);
+
+            // Set the generated text in the user session.
+            facesContext.getExternalContext().getSessionMap().put(
+                    captchaSessionKeyName, captchaText);
+        }
+        finally
+        {
+            out.close();
+            facesContext.responseComplete();
+        }
+    }
+}

Added: myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha/util/CAPTCHAImageGenerator.java
URL: http://svn.apache.org/viewvc/myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha/util/CAPTCHAImageGenerator.java?rev=939128&view=auto
==============================================================================
--- myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha/util/CAPTCHAImageGenerator.java (added)
+++ myfaces/tomahawk/trunk/core20/src/main/java/org/apache/myfaces/custom/captcha/util/CAPTCHAImageGenerator.java Wed Apr 28 22:57:24 2010
@@ -0,0 +1,290 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.custom.captcha.util;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.font.TextLayout;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.Random;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.batik.ext.awt.image.codec.PNGEncodeParam;
+import org.apache.batik.ext.awt.image.codec.PNGImageEncoder;
+
+/**
+ * This class is responsible for generating the CAPTCHA image.
+ * 
+ * @since 1.1.7
+ */
+public class CAPTCHAImageGenerator
+{
+
+    //private static final Color startingColor = new Color(150, 50, 150);
+    //private static final Color endingColor = new Color(255, 255, 255);
+
+    /*
+    * A helper method to draw the captcha text on the generated image.
+    */
+    private void drawTextOnImage(Graphics2D graphics, String captchaText)
+    {
+
+        Font font;
+        TextLayout textLayout;
+        double currentFontStatus = Math.random();
+
+        // Generate random font status.
+        if (currentFontStatus >= 0.5)
+        {
+            font = new Font("Arial", Font.PLAIN, 60);
+        }
+        else
+        {
+            font = new Font("Arial", Font.BOLD, 60);
+        }
+
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                RenderingHints.VALUE_ANTIALIAS_ON);
+        textLayout = new TextLayout(captchaText, font, graphics
+                .getFontRenderContext());
+
+        textLayout.draw(graphics, CAPTCHAConstants.TEXT_X_COORDINATE,
+                CAPTCHAConstants.TEXT_Y_COORDINATE);
+    }
+
+    /*
+    * A helper method to apply noise on the generated image.
+    */
+    private void applyNoiseOnImage(Graphics2D graphics, int bufferedImageWidth,
+            int bufferedImageHeight, Color startingColor, Color endingColor)
+    {
+
+        // Applying shear.
+        applyShear(graphics, bufferedImageWidth, bufferedImageHeight,
+                startingColor, endingColor);
+
+        // Drawing a broken line on the image.
+        drawBrokenLineOnImage(graphics);
+    }
+
+    /*
+    * This helper method is used for applying current gradient paint to the
+    * Graphics2D object.
+    */
+    private static void applyCurrentGradientPaint(Graphics2D graphics,
+            int width, int height, Color startingColor, Color endingColor)
+    {
+
+        GradientPaint gradientPaint = new GradientPaint(0, 0, startingColor,
+                width, height, endingColor);
+
+        graphics.setPaint(gradientPaint);
+    }
+
+    /**
+     * This method generates the CAPTCHA image. 
+     * @param response
+     * @param captchaText
+     * @param startingColor
+     * @param endingColor
+     * @throws IOException
+     */
+    public void generateImage(HttpServletResponse response, String captchaText,
+            Color startingColor, Color endingColor) throws IOException
+    {
+
+        BufferedImage bufferedImage;
+        Graphics2D graphics;
+        PNGEncodeParam param;
+        PNGImageEncoder captchaPNGImage;
+
+        // Create the CAPTCHA Image.
+        bufferedImage = new BufferedImage(
+                CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH,
+                CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT,
+                BufferedImage.TYPE_BYTE_INDEXED);
+
+        // Setup the graphics object.
+        graphics = bufferedImage.createGraphics();
+
+        applyCurrentGradientPaint(graphics, bufferedImage.getWidth(),
+                bufferedImage.getHeight(), startingColor, endingColor);
+
+        graphics.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage
+                .getHeight());
+
+        graphics.setColor(Color.black);
+
+        // Draw text on the CAPTCHA image.
+        drawTextOnImage(graphics, captchaText);
+
+        // Apply noise on the CAPTCHA image.
+        applyNoiseOnImage(graphics, bufferedImage.getWidth(), bufferedImage
+                .getHeight(), startingColor, endingColor);
+
+        // Draw the image border.
+        drawBorders(graphics, bufferedImage.getWidth(), bufferedImage
+                .getHeight());
+
+        // Set the reponse content type to jpeg.
+        response.setContentType("image/jpg");
+
+        param = PNGEncodeParam.getDefaultEncodeParam(bufferedImage);
+        captchaPNGImage = new PNGImageEncoder(response.getOutputStream(), param);
+
+        captchaPNGImage.encode(bufferedImage);
+    }
+
+    /*
+    * This helper method is used for drawing a thick line on the image.
+    */
+    private void drawThickLineOnImage(Graphics graphics, int x1, int y1,
+            int x2, int y2)
+    {
+
+        int dX = x2 - x1;
+        int dY = y2 - y1;
+        int xPoints[] = new int[4];
+        int yPoints[] = new int[4];
+        int thickness = 2;
+
+        double lineLength = Math.sqrt(dX * dX + dY * dY);
+        double scale = (double) (thickness) / (2 * lineLength);
+        double ddx = -scale * (double) dY;
+        double ddy = scale * (double) dX;
+
+        graphics.setColor(Color.black);
+
+        ddx += (ddx > 0) ? 0.5 : -0.5;
+        ddy += (ddy > 0) ? 0.5 : -0.5;
+        dX = (int) ddx;
+        dY = (int) ddy;
+
+        xPoints[0] = x1 + dX;
+        yPoints[0] = y1 + dY;
+        xPoints[1] = x1 - dX;
+        yPoints[1] = y1 - dY;
+        xPoints[2] = x2 - dX;
+        yPoints[2] = y2 - dY;
+        xPoints[3] = x2 + dX;
+        yPoints[3] = y2 + dY;
+
+        graphics.fillPolygon(xPoints, yPoints, 4);
+    }
+
+    /*
+    * This helper method is used for drawing a broken line on the image.
+    */
+    private void drawBrokenLineOnImage(Graphics2D graphics)
+    {
+
+        int yPoint1;
+        int yPoint2;
+        int yPoint3;
+        int yPoint4;
+        int yPoint5;
+        Random random = new Random();
+
+        // Random Y Points.
+        yPoint1 = random.nextInt(CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT);
+        yPoint2 = random.nextInt(CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT);
+        yPoint3 = CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT / 2;
+        yPoint4 = random.nextInt(CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT);
+        yPoint5 = random.nextInt(CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT);
+
+        // Draw the random broken line.
+        drawThickLineOnImage(graphics, 0, yPoint1,
+                CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH / 4, yPoint2);
+        drawThickLineOnImage(graphics,
+                CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH / 4, yPoint2,
+                CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH / 2, yPoint3);
+        drawThickLineOnImage(graphics,
+                CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH / 2, yPoint3,
+                3 * CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH / 4, yPoint4);
+        drawThickLineOnImage(graphics,
+                3 * CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH / 4, yPoint4,
+                CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH, yPoint5);
+    }
+
+    /*
+    * This helper method is used for calculating the delta of the shearing
+    * equation.
+    */
+    private double getDelta(int period, double i, double phase, double frames)
+    {
+        return (double) (period / 2)
+                * Math.sin(i / (double) period
+                        + (2 * CAPTCHAConstants.PI * phase) / frames);
+    }
+
+    /*
+    * This helper method is used for applying shear on the image.
+    */
+    private void applyShear(Graphics2D graphics, int bufferedImageWidth,
+            int bufferedImageHeight, Color startingColor, Color endingColor)
+    {
+
+        int periodValue = 20;
+        int numberOfFrames = 15;
+        int phaseNumber = 7;
+        double deltaX;
+        double deltaY;
+
+        applyCurrentGradientPaint(graphics, bufferedImageWidth,
+                bufferedImageHeight, startingColor, endingColor);
+
+        for (int i = 0; i < bufferedImageWidth; ++i)
+        {
+            deltaX = getDelta(periodValue, i, phaseNumber, numberOfFrames);
+            graphics.copyArea(i, 0, 1, bufferedImageHeight, 0, (int) deltaX);
+            graphics.drawLine(i, (int) deltaX, i, 0);
+            graphics.drawLine(i, (int) deltaX + bufferedImageHeight, i,
+                    bufferedImageHeight);
+        }
+
+        for (int i = 0; i < bufferedImageHeight; ++i)
+        {
+            deltaY = getDelta(periodValue, i, phaseNumber, numberOfFrames);
+            graphics.copyArea(0, i, bufferedImageWidth, 1, (int) deltaY, 0);
+            graphics.drawLine((int) deltaY, i, 0, i);
+            graphics.drawLine((int) deltaY + bufferedImageWidth, i,
+                    bufferedImageWidth, i);
+        }
+    }
+
+    /*
+    * This helper method is used for drawing the borders the image.
+    */
+    private void drawBorders(Graphics2D graphics, int width, int height)
+    {
+        graphics.setColor(Color.black);
+
+        graphics.drawLine(0, 0, 0, width - 1);
+        graphics.drawLine(0, 0, width - 1, 0);
+        graphics.drawLine(0, height - 1, width, height - 1);
+        graphics.drawLine(width - 1, height - 1, width - 1, 0);
+    }
+
+}