View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.custom.captcha;
20  
21  import java.awt.Color;
22  import java.io.IOException;
23  import java.util.Map;
24  
25  import javax.faces.FacesException;
26  import javax.faces.FactoryFinder;
27  import javax.faces.component.UIComponent;
28  import javax.faces.context.FacesContext;
29  import javax.faces.context.FacesContextFactory;
30  import javax.faces.context.ResponseStream;
31  import javax.faces.context.ResponseWriter;
32  import javax.faces.lifecycle.Lifecycle;
33  import javax.faces.lifecycle.LifecycleFactory;
34  import javax.faces.render.Renderer;
35  import javax.servlet.ServletContext;
36  import javax.servlet.http.HttpServletRequest;
37  import javax.servlet.http.HttpServletResponse;
38  
39  import org.apache.myfaces.component.html.util.HtmlComponentUtils;
40  import org.apache.myfaces.component.html.util.ParameterResourceHandler;
41  import org.apache.myfaces.custom.captcha.util.CAPTCHAConstants;
42  import org.apache.myfaces.custom.captcha.util.CAPTCHAImageGenerator;
43  import org.apache.myfaces.custom.captcha.util.CAPTCHAResponseStream;
44  import org.apache.myfaces.custom.captcha.util.CAPTCHATextGenerator;
45  import org.apache.myfaces.custom.captcha.util.ColorGenerator;
46  import org.apache.myfaces.renderkit.html.util.AddResource;
47  import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
48  import org.apache.myfaces.renderkit.html.util.ResourceLoader;
49  
50  import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
51  
52  /**
53   *
54   * @JSFRenderer
55   *   renderKitId = "HTML_BASIC"
56   *   family = "org.apache.myfaces.CAPTCHA"
57   *   type = "org.apache.myfaces.CAPTCHA"
58   * @since 1.1.7
59   * @author Hazem Saleh
60   *
61   */
62  public class CAPTCHARenderer extends Renderer implements ResourceLoader
63  {
64  
65      public void encodeBegin(FacesContext context, UIComponent component)
66              throws IOException
67      {
68  
69          CAPTCHAComponent captchaComponent = (CAPTCHAComponent) component;
70  
71          generateImageTag(context, captchaComponent);
72      }
73  
74      public void encodeEnd(FacesContext context, UIComponent component)
75              throws IOException
76      {
77          super.encodeEnd(context, component);
78      }
79  
80      /*
81       * This helper method is used for generating the img tag that will
82       * use the (AddResource) to generate the url of the generated image.
83       */
84      private void generateImageTag(FacesContext context,
85              CAPTCHAComponent component) throws IOException
86      {
87  
88          AddResource addResource;
89          ResponseWriter writer = context.getResponseWriter();
90          Map params = HtmlComponentUtils.getParameterMap(component);
91          String url;
92          String captchaSessionKeyName = component.getCaptchaSessionKeyName();
93          String width = component.getImageWidth();
94          String height = component.getImageHeight();
95  
96          // determine width and height of the generated image.
97          if (width == null)
98          {
99              width = CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH + "";
100         }
101 
102         if (height == null)
103         {
104             height = CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT + "";
105         }
106 
107         writer.startElement(HTML.IMG_ELEM, component);
108 
109         // constructing the parameter map to be passed to the (AddResource).
110         if (captchaSessionKeyName != null)
111         {
112             params.put(CAPTCHAComponent.ATTRIBUTE_CAPTCHA_SESSION_KEY_NAME,
113                     captchaSessionKeyName);
114         }
115 
116         // write the url to trigger the (AddResource).
117         addResource = AddResourceFactory.getInstance(context);
118 
119         url = context.getExternalContext().encodeResourceURL(
120                 addResource.getResourceUri(context,
121                         new ParameterResourceHandler(this.getClass(), params)));
122 
123         // adding dummy parameter to prevent caching.
124         writer.writeAttribute(HTML.SRC_ATTR, url + "&dummyParameter="
125                 + System.currentTimeMillis(), null);
126 
127         // write rest of attributes.
128         writer.writeAttribute(HTML.WIDTH_ATTR, width, null);
129 
130         writer.writeAttribute(HTML.HEIGHT_ATTR, height, null);
131 
132         writer.endElement(HTML.IMG_ELEM);
133     }
134 
135     /*
136      * This method is implemented to be called from the (AddResource).
137      * It wraps the CAPTCHA image generation.
138      */
139     public void serveResource(ServletContext servletContext,
140             HttpServletRequest request, HttpServletResponse response,
141             String resourceUri) throws IOException
142     {
143 
144         // get the FacesContext from the ServletContext.
145         FacesContextFactory facesContextFactory = (FacesContextFactory) FactoryFinder
146                 .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
147         LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
148                 .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
149         Lifecycle lifecycle = lifecycleFactory.getLifecycle(HtmlComponentUtils
150                 .getLifecycleId(servletContext));
151         FacesContext facesContext = facesContextFactory.getFacesContext(
152                 servletContext, request, response, lifecycle);
153         facesContext.setResponseStream(new CAPTCHAResponseStream(response
154                 .getOutputStream()));
155 
156         // render the CAPTCHA.
157         try
158         {
159             try
160             {
161                 renderCAPTCHA(facesContext);
162             }
163             catch (IOException e)
164             {
165                 throw new FacesException("Could not render the CAPTCHA : "
166                         + e.getMessage(), e);
167             }
168             facesContext.getResponseStream().close();
169         }
170         finally
171         {
172             facesContext.release();
173         }
174     }
175 
176     /*
177      * This method is used for rendering the CAPTCHA component.
178      */
179     protected void renderCAPTCHA(FacesContext facesContext) throws IOException
180     {
181 
182         // getting CAPTCHA attributes.
183         HttpServletResponse response = (HttpServletResponse) facesContext
184                 .getExternalContext().getResponse();
185         ResponseStream out = facesContext.getResponseStream();
186         Map requestMap = facesContext.getExternalContext()
187                 .getRequestParameterMap();
188         String captchaSessionKeyName = requestMap.get(
189                 CAPTCHAComponent.ATTRIBUTE_CAPTCHA_SESSION_KEY_NAME).toString();
190 
191         // construct the CAPTCHA image generator object.
192         CAPTCHAImageGenerator captchaImageGenerator = new CAPTCHAImageGenerator();
193 
194         try
195         {
196             String captchaText;
197             Color endingColor = ColorGenerator.generateRandomColor(null);
198             Color startingColor = ColorGenerator
199                     .generateRandomColor(endingColor);
200 
201             // Generate random CAPTCHA text.
202             captchaText = CAPTCHATextGenerator.generateRandomText();
203 
204             // Set the generated text in the user session.
205             facesContext.getExternalContext().getSessionMap().put(
206                     captchaSessionKeyName, captchaText);
207 
208             // Generate the image, the BG color is randomized from starting to ending colors.
209             captchaImageGenerator.generateImage(response, captchaText,
210                     startingColor, endingColor);
211         }
212         finally
213         {
214             out.close();
215             facesContext.responseComplete();
216         }
217     }
218 }