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);
+ }
+
+}